| Directory: | ./ |
|---|---|
| File: | sql/sql_optimizer.cc |
| Date: | 2022-12-13 11:44:05 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 4247 | 4409 | 96.3% |
| Branches: | 5411 | 7293 | 74.2% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* Copyright (c) 2000, 2022, Oracle and/or its affiliates. | ||
| 2 | |||
| 3 | This program is free software; you can redistribute it and/or modify | ||
| 4 | it under the terms of the GNU General Public License, version 2.0, | ||
| 5 | as published by the Free Software Foundation. | ||
| 6 | |||
| 7 | This program is also distributed with certain software (including | ||
| 8 | but not limited to OpenSSL) that is licensed under separate terms, | ||
| 9 | as designated in a particular file or component or in included license | ||
| 10 | documentation. The authors of MySQL hereby grant you an additional | ||
| 11 | permission to link the program and your derivative works with the | ||
| 12 | separately licensed software that they have included with MySQL. | ||
| 13 | |||
| 14 | This program is distributed in the hope that it will be useful, | ||
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | GNU General Public License, version 2.0, for more details. | ||
| 18 | |||
| 19 | You should have received a copy of the GNU General Public License | ||
| 20 | along with this program; if not, write to the Free Software | ||
| 21 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
| 22 | |||
| 23 | /** | ||
| 24 | @file | ||
| 25 | |||
| 26 | @brief Optimize query expressions: Make optimal table join order, select | ||
| 27 | optimal access methods per table, apply grouping, sorting and | ||
| 28 | limit processing. | ||
| 29 | |||
| 30 | @defgroup Query_Optimizer Query Optimizer | ||
| 31 | @{ | ||
| 32 | */ | ||
| 33 | |||
| 34 | #include "sql/sql_optimizer.h" | ||
| 35 | #include "sql/sql_optimizer_internal.h" | ||
| 36 | |||
| 37 | #include <limits.h> | ||
| 38 | #include <algorithm> | ||
| 39 | #include <atomic> | ||
| 40 | #include <deque> | ||
| 41 | #include <new> | ||
| 42 | #include <string> | ||
| 43 | #include <utility> | ||
| 44 | #include <vector> | ||
| 45 | |||
| 46 | #include "field_types.h" // enum_field_types | ||
| 47 | #include "ft_global.h" | ||
| 48 | #include "m_ctype.h" | ||
| 49 | #include "mem_root_deque.h" | ||
| 50 | #include "memory_debugging.h" | ||
| 51 | #include "my_bit.h" // my_count_bits | ||
| 52 | #include "my_bitmap.h" | ||
| 53 | #include "my_compiler.h" | ||
| 54 | #include "my_dbug.h" | ||
| 55 | #include "my_inttypes.h" | ||
| 56 | #include "my_sqlcommand.h" | ||
| 57 | #include "my_sys.h" | ||
| 58 | #include "mysql/udf_registration_types.h" | ||
| 59 | #include "mysql_com.h" | ||
| 60 | #include "mysqld_error.h" | ||
| 61 | #include "sql/check_stack.h" | ||
| 62 | #include "sql/current_thd.h" | ||
| 63 | #include "sql/debug_sync.h" // DEBUG_SYNC | ||
| 64 | #include "sql/derror.h" // ER_THD | ||
| 65 | #include "sql/enum_query_type.h" | ||
| 66 | #include "sql/error_handler.h" // Functional_index_error_handler | ||
| 67 | #include "sql/handler.h" | ||
| 68 | #include "sql/item.h" | ||
| 69 | #include "sql/item_cmpfunc.h" | ||
| 70 | #include "sql/item_func.h" | ||
| 71 | #include "sql/item_row.h" | ||
| 72 | #include "sql/item_subselect.h" | ||
| 73 | #include "sql/item_sum.h" // Item_sum | ||
| 74 | #include "sql/iterators/basic_row_iterators.h" | ||
| 75 | #include "sql/iterators/timing_iterator.h" | ||
| 76 | #include "sql/join_optimizer/access_path.h" | ||
| 77 | #include "sql/join_optimizer/join_optimizer.h" | ||
| 78 | #include "sql/key.h" | ||
| 79 | #include "sql/key_spec.h" | ||
| 80 | #include "sql/lock.h" // mysql_unlock_some_tables | ||
| 81 | #include "sql/mysqld.h" // stage_optimizing | ||
| 82 | #include "sql/nested_join.h" | ||
| 83 | #include "sql/opt_costmodel.h" | ||
| 84 | #include "sql/opt_explain.h" // join_type_str | ||
| 85 | #include "sql/opt_hints.h" // hint_table_state | ||
| 86 | #include "sql/opt_trace.h" // Opt_trace_object | ||
| 87 | #include "sql/opt_trace_context.h" | ||
| 88 | #include "sql/parse_tree_node_base.h" | ||
| 89 | #include "sql/parser_yystype.h" | ||
| 90 | #include "sql/query_options.h" | ||
| 91 | #include "sql/query_result.h" | ||
| 92 | #include "sql/range_optimizer/partition_pruning.h" | ||
| 93 | #include "sql/range_optimizer/path_helpers.h" | ||
| 94 | #include "sql/range_optimizer/range_optimizer.h" | ||
| 95 | #include "sql/sql_base.h" // init_ftfuncs | ||
| 96 | #include "sql/sql_bitmap.h" | ||
| 97 | #include "sql/sql_class.h" | ||
| 98 | #include "sql/sql_const.h" | ||
| 99 | #include "sql/sql_const_folding.h" | ||
| 100 | #include "sql/sql_error.h" | ||
| 101 | #include "sql/sql_join_buffer.h" // JOIN_CACHE | ||
| 102 | #include "sql/sql_planner.h" // calculate_condition_filter | ||
| 103 | #include "sql/sql_test.h" // print_where | ||
| 104 | #include "sql/sql_tmp_table.h" | ||
| 105 | #include "sql/system_variables.h" | ||
| 106 | #include "sql/table.h" | ||
| 107 | #include "sql/thd_raii.h" | ||
| 108 | #include "sql/window.h" | ||
| 109 | #include "sql_string.h" | ||
| 110 | #include "template_utils.h" | ||
| 111 | |||
| 112 | using std::max; | ||
| 113 | using std::min; | ||
| 114 | |||
| 115 | const char *antijoin_null_cond = "<ANTIJOIN-NULL>"; | ||
| 116 | |||
| 117 | static bool optimize_semijoin_nests_for_materialization(JOIN *join); | ||
| 118 | static void calculate_materialization_costs(JOIN *join, TABLE_LIST *sj_nest, | ||
| 119 | uint n_tables, | ||
| 120 | Semijoin_mat_optimize *sjm); | ||
| 121 | static bool make_join_query_block(JOIN *join, Item *item); | ||
| 122 | static bool list_contains_unique_index(JOIN_TAB *tab, | ||
| 123 | bool (*find_func)(Field *, void *), | ||
| 124 | void *data); | ||
| 125 | static bool find_field_in_item_list(Field *field, void *data); | ||
| 126 | static bool find_field_in_order_list(Field *field, void *data); | ||
| 127 | static TABLE *get_sort_by_table(ORDER *a, ORDER *b, TABLE_LIST *tables); | ||
| 128 | static void trace_table_dependencies(Opt_trace_context *trace, | ||
| 129 | JOIN_TAB *join_tabs, uint table_count); | ||
| 130 | static bool update_ref_and_keys(THD *thd, Key_use_array *keyuse, | ||
| 131 | JOIN_TAB *join_tab, uint tables, Item *cond, | ||
| 132 | table_map normal_tables, | ||
| 133 | Query_block *query_block, | ||
| 134 | SARGABLE_PARAM **sargables); | ||
| 135 | static bool pull_out_semijoin_tables(JOIN *join); | ||
| 136 | static void add_loose_index_scan_and_skip_scan_keys(JOIN *join, | ||
| 137 | JOIN_TAB *join_tab); | ||
| 138 | static ha_rows get_quick_record_count(THD *thd, JOIN_TAB *tab, ha_rows limit); | ||
| 139 | static bool only_eq_ref_tables(JOIN *join, ORDER *order, table_map tables, | ||
| 140 | table_map *cached_eq_ref_tables, | ||
| 141 | table_map *eq_ref_tables); | ||
| 142 | static bool setup_join_buffering(JOIN_TAB *tab, JOIN *join, uint no_jbuf_after); | ||
| 143 | |||
| 144 | static bool test_if_skip_sort_order(JOIN_TAB *tab, ORDER_with_src &order, | ||
| 145 | ha_rows select_limit, const bool no_changes, | ||
| 146 | const Key_map *map, int *best_idx); | ||
| 147 | |||
| 148 | static Item_func_match *test_if_ft_index_order(ORDER *order); | ||
| 149 | |||
| 150 | static uint32 get_key_length_tmp_table(Item *item); | ||
| 151 | static bool can_switch_from_ref_to_range(THD *thd, JOIN_TAB *tab, | ||
| 152 | enum_order ordering, | ||
| 153 | bool recheck_range); | ||
| 154 | |||
| 155 | static bool has_not_null_predicate(Item *cond, Item_field *not_null_item); | ||
| 156 | |||
| 157 | 9125947 | JOIN::JOIN(THD *thd_arg, Query_block *select) | |
| 158 | 9125947 | : query_block(select), | |
| 159 | 9125947 | thd(thd_arg), | |
| 160 | // @todo Can this be substituted with select->is_explicitly_grouped()? | ||
| 161 | 18251936 | grouped(select->is_explicitly_grouped()), | |
| 162 | // Inner tables may always be considered to be constant: | ||
| 163 | 9125968 | const_table_map(INNER_TABLE_BIT), | |
| 164 | 9125968 | found_const_table_map(INNER_TABLE_BIT), | |
| 165 | // Needed in case optimizer short-cuts, set properly in | ||
| 166 | // make_tmp_tables_info() | ||
| 167 | 9125968 | fields(&select->fields), | |
| 168 | 9125977 | tmp_table_param(thd_arg->mem_root), | |
| 169 | 9125954 | lock(thd->lock), | |
| 170 | // @todo Can this be substituted with select->is_implicitly_grouped()? | ||
| 171 | 9125954 | implicit_grouping(select->is_implicitly_grouped()), | |
| 172 | 9125966 | select_distinct(select->is_distinct()), | |
| 173 | 9125974 | keyuse_array(thd->mem_root), | |
| 174 | 9125955 | order(select->order_list.first, ESC_ORDER_BY), | |
| 175 | 9125954 | group_list(select->group_list.first, ESC_GROUP_BY), | |
| 176 | 9125953 | m_windows(select->m_windows), | |
| 177 | /* | ||
| 178 | Those four members are meaningless before JOIN::optimize(), so force a | ||
| 179 | crash if they are used before that. | ||
| 180 | */ | ||
| 181 | 9125952 | where_cond(reinterpret_cast<Item *>(1)), | |
| 182 | 9125952 | having_cond(reinterpret_cast<Item *>(1)), | |
| 183 | 9125952 | having_for_explain(reinterpret_cast<Item *>(1)), | |
| 184 | 9125952 | tables_list(reinterpret_cast<TABLE_LIST *>(1)), | |
| 185 | 9125952 | current_ref_item_slice(REF_SLICE_SAVED_BASE), | |
| 186 |
2/4✓ Branch 0 taken 9125954 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9125955 times.
✗ Branch 3 not taken.
|
36503845 | with_json_agg(select->json_agg_func_used()) { |
| 187 | 9125963 | rollup_state = RollupState::NONE; | |
| 188 |
2/2✓ Branch 0 taken 553479 times.
✓ Branch 1 taken 8572484 times.
|
9125963 | if (select->order_list.first) explain_flags.set(ESC_ORDER_BY, ESP_EXISTS); |
| 189 |
2/2✓ Branch 0 taken 23651 times.
✓ Branch 1 taken 9102312 times.
|
9125963 | if (select->group_list.first) explain_flags.set(ESC_GROUP_BY, ESP_EXISTS); |
| 190 |
2/2✓ Branch 0 taken 4231 times.
✓ Branch 1 taken 9121749 times.
|
9125963 | if (select->is_distinct()) explain_flags.set(ESC_DISTINCT, ESP_EXISTS); |
| 191 |
2/2✓ Branch 0 taken 2450 times.
✓ Branch 1 taken 9123530 times.
|
9125980 | if (m_windows.elements > 0) explain_flags.set(ESC_WINDOWING, ESP_EXISTS); |
| 192 | // Calculate the number of groups | ||
| 193 |
2/2✓ Branch 0 taken 31362 times.
✓ Branch 1 taken 9125965 times.
|
9157327 | for (ORDER *group = group_list.order; group; group = group->next) |
| 194 | 31362 | send_group_parts++; | |
| 195 | 9125965 | } | |
| 196 | |||
| 197 | 523901 | bool JOIN::alloc_ref_item_slice(THD *thd_arg, int sliceno) { | |
| 198 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 523901 times.
|
523901 | assert(sliceno > 0); |
| 199 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 523901 times.
|
523901 | assert(ref_items[sliceno].is_null()); |
| 200 | 523901 | size_t count = ref_items[0].size(); | |
| 201 | 523900 | Item **slice = thd_arg->mem_root->ArrayAlloc<Item *>(count); | |
| 202 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 523901 times.
|
523901 | if (slice == nullptr) return true; |
| 203 | 523901 | ref_items[sliceno] = Ref_item_array(slice, count); | |
| 204 | 523901 | return false; | |
| 205 | } | ||
| 206 | |||
| 207 | 9008570 | bool JOIN::alloc_indirection_slices() { | |
| 208 | 9008570 | const int num_slices = REF_SLICE_WIN_1 + m_windows.elements; | |
| 209 | |||
| 210 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9008570 times.
|
9008570 | assert(ref_items == nullptr); |
| 211 | 9008570 | ref_items = (*THR_MALLOC)->ArrayAlloc<Ref_item_array>(num_slices); | |
| 212 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9008609 times.
|
9008609 | if (ref_items == nullptr) return true; |
| 213 | |||
| 214 | 9008611 | tmp_fields = | |
| 215 | 9008609 | (*THR_MALLOC) | |
| 216 | 9008616 | ->ArrayAlloc<mem_root_deque<Item *>>(num_slices, *THR_MALLOC); | |
| 217 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9008611 times.
|
9008611 | if (tmp_fields == nullptr) return true; |
| 218 | |||
| 219 | 9008611 | return false; | |
| 220 | } | ||
| 221 | |||
| 222 | /** | ||
| 223 | The List<Item_equal> in COND_EQUAL partially overlaps with the argument list | ||
| 224 | in various Item_cond via C-style casts. However, the hypergraph optimizer can | ||
| 225 | modify the lists in Item_cond (by calling compile()), causing an Item_equal to | ||
| 226 | be replaced with Item_func_eq, and this can cause a List<Item_equal> not to | ||
| 227 | contain Item_equal pointers anymore. This is is obviously bad if anybody wants | ||
| 228 | to actually look into these lists after optimization (in particular, NDB | ||
| 229 | wants this). | ||
| 230 | |||
| 231 | Since untangling this spaghetti seems very hard, we solve it by brute force: | ||
| 232 | Make a copy of all the COND_EQUAL lists, so that they no longer reach into the | ||
| 233 | Item_cond. This allows us to modify the Item_cond at will. | ||
| 234 | */ | ||
| 235 | 107 | static void SaveCondEqualLists(COND_EQUAL *cond_equal) { | |
| 236 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 11 times.
|
107 | if (cond_equal == nullptr) { |
| 237 | 96 | return; | |
| 238 | } | ||
| 239 | 11 | List<Item_equal> copy; | |
| 240 |
5/8✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✓ Branch 7 taken 11 times.
|
20 | for (Item_equal &item : cond_equal->current_level) { |
| 241 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | copy.push_back(&item); |
| 242 | } | ||
| 243 | 11 | cond_equal->current_level = std::move(copy); | |
| 244 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | SaveCondEqualLists(cond_equal->upper_levels); |
| 245 | } | ||
| 246 | |||
| 247 | /** | ||
| 248 | Optimizes one query block into a query execution plan (QEP.) | ||
| 249 | |||
| 250 | This is the entry point to the query optimization phase. This phase | ||
| 251 | applies both logical (equivalent) query rewrites, cost-based join | ||
| 252 | optimization, and rule-based access path selection. Once an optimal | ||
| 253 | plan is found, the member function creates/initializes all | ||
| 254 | structures needed for query execution. The main optimization phases | ||
| 255 | are outlined below: | ||
| 256 | |||
| 257 | -# Logical transformations: | ||
| 258 | - Outer to inner joins transformation. | ||
| 259 | - Equality/constant propagation. | ||
| 260 | - Partition pruning. | ||
| 261 | - COUNT(*), MIN(), MAX() constant substitution in case of | ||
| 262 | implicit grouping. | ||
| 263 | - ORDER BY optimization. | ||
| 264 | -# Perform cost-based optimization of table order and access path | ||
| 265 | selection. See JOIN::make_join_plan() | ||
| 266 | -# Post-join order optimization: | ||
| 267 | - Create optimal table conditions from the where clause and the | ||
| 268 | join conditions. | ||
| 269 | - Inject outer-join guarding conditions. | ||
| 270 | - Adjust data access methods after determining table condition | ||
| 271 | (several times.) | ||
| 272 | - Optimize ORDER BY/DISTINCT. | ||
| 273 | -# Code generation | ||
| 274 | - Set data access functions. | ||
| 275 | - Try to optimize away sorting/distinct. | ||
| 276 | - Setup temporary table usage for grouping and/or sorting. | ||
| 277 | |||
| 278 | @retval false Success. | ||
| 279 | @retval true Error, error code saved in member JOIN::error. | ||
| 280 | */ | ||
| 281 | 9008627 | bool JOIN::optimize(bool finalize_access_paths) { | |
| 282 |
1/2✓ Branch 0 taken 9008677 times.
✗ Branch 1 not taken.
|
9008627 | DBUG_TRACE; |
| 283 | |||
| 284 | 9008677 | uint no_jbuf_after = UINT_MAX; | |
| 285 | |||
| 286 |
5/6✓ Branch 0 taken 1889050 times.
✓ Branch 1 taken 7119627 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1889050 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
9008677 | assert(query_block->leaf_table_count == 0 || |
| 287 | thd->lex->is_query_tables_locked() || | ||
| 288 | query_block == query_expression()->fake_query_block); | ||
| 289 |
4/6✓ Branch 0 taken 9008649 times.
✓ Branch 1 taken 29 times.
✓ Branch 2 taken 9008653 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9008656 times.
✗ Branch 5 not taken.
|
9008678 | assert(tables == 0 && primary_tables == 0 && tables_list == (TABLE_LIST *)1); |
| 290 | |||
| 291 | // to prevent double initialization on EXPLAIN | ||
| 292 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9008656 times.
|
9008656 | if (optimized) return false; |
| 293 | |||
| 294 |
3/4✓ Branch 0 taken 8991033 times.
✓ Branch 1 taken 17623 times.
✓ Branch 2 taken 8991052 times.
✗ Branch 3 not taken.
|
9008656 | DEBUG_SYNC(thd, "before_join_optimize"); |
| 295 | |||
| 296 |
1/2✓ Branch 0 taken 9008671 times.
✗ Branch 1 not taken.
|
9008675 | THD_STAGE_INFO(thd, stage_optimizing); |
| 297 | |||
| 298 | 9008671 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 299 |
1/2✓ Branch 0 taken 9008675 times.
✗ Branch 1 not taken.
|
9008671 | Opt_trace_object trace_wrapper(trace); |
| 300 |
1/2✓ Branch 0 taken 9008672 times.
✗ Branch 1 not taken.
|
9008675 | Opt_trace_object trace_optimize(trace, "join_optimization"); |
| 301 |
1/2✓ Branch 0 taken 9008664 times.
✗ Branch 1 not taken.
|
9008672 | trace_optimize.add_select_number(query_block->select_number); |
| 302 |
1/2✓ Branch 0 taken 9008646 times.
✗ Branch 1 not taken.
|
9008664 | Opt_trace_array trace_steps(trace, "steps"); |
| 303 | |||
| 304 |
1/2✓ Branch 0 taken 9008676 times.
✗ Branch 1 not taken.
|
9008646 | count_field_types(query_block, &tmp_table_param, *fields, false, false); |
| 305 | |||
| 306 |
5/6✓ Branch 0 taken 371697 times.
✓ Branch 1 taken 8636979 times.
✓ Branch 2 taken 351640 times.
✓ Branch 3 taken 20057 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 351640 times.
|
9008676 | assert(tmp_table_param.sum_func_count == 0 || !group_list.empty() || |
| 307 | implicit_grouping); | ||
| 308 | |||
| 309 | 9008676 | const bool has_windows = m_windows.elements != 0; | |
| 310 | |||
| 311 |
7/8✓ Branch 0 taken 2450 times.
✓ Branch 1 taken 9006226 times.
✓ Branch 2 taken 2450 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 53 times.
✓ Branch 5 taken 2397 times.
✓ Branch 6 taken 53 times.
✓ Branch 7 taken 9008623 times.
|
9008676 | if (has_windows && Window::setup_windows2(thd, &m_windows)) |
| 312 | 53 | return true; /* purecov: inspected */ | |
| 313 | |||
| 314 |
5/8✓ Branch 0 taken 377 times.
✓ Branch 1 taken 9008246 times.
✓ Branch 2 taken 377 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 377 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9008623 times.
|
9008623 | if (query_block->olap == ROLLUP_TYPE && optimize_rollup()) |
| 315 | ✗ | return true; /* purecov: inspected */ | |
| 316 | |||
| 317 |
2/4✓ Branch 0 taken 9008620 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9008620 times.
|
9008623 | if (alloc_func_list()) return true; /* purecov: inspected */ |
| 318 | |||
| 319 |
2/4✓ Branch 0 taken 9008622 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9008622 times.
|
9008620 | if (query_block->get_optimizable_conditions(thd, &where_cond, &having_cond)) |
| 320 | ✗ | return true; | |
| 321 | |||
| 322 |
4/6✓ Branch 0 taken 9008583 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9008613 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1041 times.
✓ Branch 5 taken 9008613 times.
|
9009663 | for (Item_rollup_group_item *item : query_block->rollup_group_items) { |
| 323 |
1/2✓ Branch 0 taken 1041 times.
✗ Branch 1 not taken.
|
1041 | rollup_group_items.push_back(item); |
| 324 | } | ||
| 325 |
4/6✓ Branch 0 taken 9008617 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9008593 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 348 times.
✓ Branch 5 taken 9008593 times.
|
9008961 | for (Item_rollup_sum_switcher *item : query_block->rollup_sums) { |
| 326 |
1/2✓ Branch 0 taken 348 times.
✗ Branch 1 not taken.
|
348 | rollup_sums.push_back(item); |
| 327 | } | ||
| 328 | |||
| 329 | 9008593 | set_optimized(); | |
| 330 | |||
| 331 | 9008576 | tables_list = query_block->leaf_tables; | |
| 332 | |||
| 333 |
2/4✓ Branch 0 taken 9008610 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9008610 times.
|
9008576 | if (alloc_indirection_slices()) return true; |
| 334 | |||
| 335 | // The base ref items from query block are assigned as JOIN's ref items | ||
| 336 | 9008610 | ref_items[REF_SLICE_ACTIVE] = query_block->base_ref_items; | |
| 337 | |||
| 338 | /* dump_TABLE_LIST_graph(query_block, query_block->leaf_tables); */ | ||
| 339 | /* | ||
| 340 | Run optimize phase for all derived tables/views used in this SELECT, | ||
| 341 | including those in semi-joins. | ||
| 342 | */ | ||
| 343 | // if (query_block->materialized_derived_table_count) { | ||
| 344 | { // WL#6570 | ||
| 345 |
2/2✓ Branch 0 taken 3976632 times.
✓ Branch 1 taken 9008569 times.
|
12985201 | for (TABLE_LIST *tl = query_block->leaf_tables; tl; tl = tl->next_leaf) { |
| 346 | 3976632 | tl->access_path_for_derived = nullptr; | |
| 347 |
2/2✓ Branch 0 taken 178532 times.
✓ Branch 1 taken 3798095 times.
|
3976632 | if (tl->is_view_or_derived()) { |
| 348 |
3/4✓ Branch 0 taken 178532 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 178513 times.
|
178532 | if (tl->optimize_derived(thd)) return true; |
| 349 |
2/2✓ Branch 0 taken 436 times.
✓ Branch 1 taken 3797661 times.
|
3798095 | } else if (tl->is_table_function()) { |
| 350 | 436 | TABLE *const table = tl->table; | |
| 351 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 401 times.
|
436 | if (!table->has_storage_handler()) { |
| 352 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if (setup_tmp_table_handler( |
| 353 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | thd, table, |
| 354 | 16 | query_block->active_options() | TMP_TABLE_ALL_COLUMNS)) | |
| 355 | ✗ | return true; /* purecov: inspected */ | |
| 356 | } | ||
| 357 | |||
| 358 | 417 | table->file->stats.records = 2; | |
| 359 | } | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 |
2/2✓ Branch 0 taken 112 times.
✓ Branch 1 taken 9008457 times.
|
9008569 | if (thd->lex->using_hypergraph_optimizer) { |
| 364 | // The hypergraph optimizer also wants all subselect items to be optimized, | ||
| 365 | // so that it has cost information to attach to filter nodes. | ||
| 366 | 112 | for (Query_expression *unit = query_block->first_inner_query_expression(); | |
| 367 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 112 times.
|
121 | unit; unit = unit->next_query_expression()) { |
| 368 | // Derived tables and const subqueries are already optimized | ||
| 369 |
2/4✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
|
18 | if (!unit->is_optimized() && |
| 370 |
2/4✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
|
9 | unit->optimize(thd, /*materialize_destination=*/nullptr, |
| 371 | /*create_iterators=*/false, | ||
| 372 | /*finalize_access_paths=*/false)) | ||
| 373 | ✗ | return true; | |
| 374 | } | ||
| 375 | |||
| 376 | // The hypergraph optimizer does not do const tables, | ||
| 377 | // nor does it evaluate subqueries during optimization. | ||
| 378 | 112 | query_block->add_active_options(OPTION_NO_CONST_TABLES | | |
| 379 | OPTION_NO_SUBQUERY_DURING_OPTIMIZATION); | ||
| 380 | } | ||
| 381 | |||
| 382 | 9008577 | has_lateral = false; | |
| 383 | |||
| 384 | /* dump_TABLE_LIST_graph(query_block, query_block->leaf_tables); */ | ||
| 385 | |||
| 386 |
4/4✓ Branch 0 taken 8452425 times.
✓ Branch 1 taken 551906 times.
✓ Branch 2 taken 8432523 times.
✓ Branch 3 taken 19917 times.
|
9004352 | row_limit = ((select_distinct || !order.empty() || !group_list.empty()) |
| 387 |
2/2✓ Branch 0 taken 9004352 times.
✓ Branch 1 taken 4225 times.
|
18012939 | ? HA_POS_ERROR |
| 388 | 8432523 | : query_expression()->select_limit_cnt); | |
| 389 | // m_select_limit is used to decide if we are likely to scan the whole table. | ||
| 390 | 9008587 | m_select_limit = query_expression()->select_limit_cnt; | |
| 391 | |||
| 392 |
2/2✓ Branch 0 taken 177 times.
✓ Branch 1 taken 9008416 times.
|
9008593 | if (query_expression()->first_query_block()->active_options() & |
| 393 | OPTION_FOUND_ROWS) { | ||
| 394 | /* | ||
| 395 | Calculate found rows (ie., keep counting rows even after we hit LIMIT) if | ||
| 396 | - LIMIT is set, and | ||
| 397 | - This is the outermost query block (for a UNION query, this is the | ||
| 398 | fake query block that contains the limit applied on the final UNION | ||
| 399 | evaluation). | ||
| 400 | */ | ||
| 401 |
2/2✓ Branch 0 taken 121 times.
✓ Branch 1 taken 56 times.
|
298 | calc_found_rows = m_select_limit != HA_POS_ERROR && |
| 402 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 95 times.
|
121 | (!query_expression()->is_union() || |
| 403 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 14 times.
|
26 | query_block == query_expression()->fake_query_block); |
| 404 | } | ||
| 405 |
4/4✓ Branch 0 taken 8998284 times.
✓ Branch 1 taken 10309 times.
✓ Branch 2 taken 88 times.
✓ Branch 3 taken 8998196 times.
|
9008593 | if (having_cond || calc_found_rows) m_select_limit = HA_POS_ERROR; |
| 406 | |||
| 407 |
6/6✓ Branch 0 taken 256 times.
✓ Branch 1 taken 9008325 times.
✓ Branch 2 taken 238 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 238 times.
✓ Branch 5 taken 9008343 times.
|
9008593 | if (query_expression()->select_limit_cnt == 0 && !calc_found_rows) { |
| 408 | 238 | zero_result_cause = "Zero limit"; | |
| 409 | 238 | best_rowcount = 0; | |
| 410 |
1/2✓ Branch 0 taken 238 times.
✗ Branch 1 not taken.
|
238 | create_access_paths_for_zero_rows(); |
| 411 | 238 | goto setup_subq_exit; | |
| 412 | } | ||
| 413 | |||
| 414 |
4/4✓ Branch 0 taken 7750052 times.
✓ Branch 1 taken 1258291 times.
✓ Branch 2 taken 5338 times.
✓ Branch 3 taken 7744714 times.
|
9008343 | if (where_cond || query_block->outer_join) { |
| 415 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 1263547 times.
|
1263575 | if (optimize_cond(thd, &where_cond, &cond_equal, |
| 416 |
1/2✓ Branch 0 taken 1263575 times.
✗ Branch 1 not taken.
|
1263629 | &query_block->top_join_list, &query_block->cond_value)) { |
| 417 | 28 | error = 1; | |
| 418 |
3/8✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
28 | DBUG_PRINT("error", ("Error from optimize_cond")); |
| 419 | 28 | return true; | |
| 420 | } | ||
| 421 |
2/2✓ Branch 0 taken 11323 times.
✓ Branch 1 taken 1252224 times.
|
1263547 | if (query_block->cond_value == Item::COND_FALSE) { |
| 422 | 11323 | zero_result_cause = "Impossible WHERE"; | |
| 423 | 11323 | best_rowcount = 0; | |
| 424 |
1/2✓ Branch 0 taken 11323 times.
✗ Branch 1 not taken.
|
11323 | create_access_paths_for_zero_rows(); |
| 425 | 11323 | goto setup_subq_exit; | |
| 426 | } | ||
| 427 | } | ||
| 428 |
2/2✓ Branch 0 taken 10245 times.
✓ Branch 1 taken 8986693 times.
|
8996938 | if (having_cond) { |
| 429 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10242 times.
|
10245 | if (optimize_cond(thd, &having_cond, &cond_equal, nullptr, |
| 430 |
1/2✓ Branch 0 taken 10245 times.
✗ Branch 1 not taken.
|
10245 | &query_block->having_value)) { |
| 431 | 3 | error = 1; | |
| 432 |
3/8✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
3 | DBUG_PRINT("error", ("Error from optimize_cond")); |
| 433 | 3 | return true; | |
| 434 | } | ||
| 435 |
2/2✓ Branch 0 taken 186 times.
✓ Branch 1 taken 10056 times.
|
10242 | if (query_block->having_value == Item::COND_FALSE) { |
| 436 | 186 | zero_result_cause = "Impossible HAVING"; | |
| 437 | 186 | best_rowcount = 0; | |
| 438 |
1/2✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
|
186 | create_access_paths_for_zero_rows(); |
| 439 | 186 | goto setup_subq_exit; | |
| 440 | } | ||
| 441 | } | ||
| 442 | |||
| 443 |
2/2✓ Branch 0 taken 8956629 times.
✓ Branch 1 taken 40120 times.
|
8996749 | if (thd->lex->sql_command == SQLCOM_INSERT_SELECT || |
| 444 |
2/2✓ Branch 0 taken 793 times.
✓ Branch 1 taken 8955836 times.
|
8956629 | thd->lex->sql_command == SQLCOM_REPLACE_SELECT) { |
| 445 | /* | ||
| 446 | Statement-based replication of INSERT ... SELECT ... LIMIT and | ||
| 447 | REPLACE ... SELECT is safe as order of row is defined with either | ||
| 448 | ORDER BY or other condition. However it is too late for it have | ||
| 449 | an impact to our decision to switch to row- based. We can only | ||
| 450 | suppress warning here. | ||
| 451 | */ | ||
| 452 |
1/2✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
|
694 | if (query_block->select_limit && query_block->select_limit->fixed && |
| 453 |
6/8✓ Branch 0 taken 694 times.
✓ Branch 1 taken 40219 times.
✓ Branch 2 taken 694 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 694 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 424 times.
✓ Branch 7 taken 40489 times.
|
42301 | query_block->select_limit->val_int() && |
| 454 |
3/4✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 424 times.
✓ Branch 3 taken 270 times.
|
694 | !is_order_deterministic(&query_block->top_join_list, where_cond, |
| 455 | order.order)) { | ||
| 456 | 424 | thd->order_deterministic = false; | |
| 457 | } | ||
| 458 | } | ||
| 459 | |||
| 460 |
7/8✓ Branch 0 taken 83698 times.
✓ Branch 1 taken 8913051 times.
✓ Branch 2 taken 83698 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 83695 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 8996746 times.
|
8996749 | if (query_block->partitioned_table_count && prune_table_partitions()) { |
| 461 | 3 | error = 1; | |
| 462 |
3/8✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
3 | DBUG_PRINT("error", ("Error from prune_partitions")); |
| 463 | 3 | return true; | |
| 464 | } | ||
| 465 | |||
| 466 | /* | ||
| 467 | Try to optimize count(*), min() and max() to const fields if | ||
| 468 | there is implicit grouping (aggregate functions but no | ||
| 469 | group_list). In this case, the result set shall only contain one | ||
| 470 | row. | ||
| 471 | */ | ||
| 472 |
6/6✓ Branch 0 taken 1877630 times.
✓ Branch 1 taken 7119116 times.
✓ Branch 2 taken 349981 times.
✓ Branch 3 taken 1527649 times.
✓ Branch 4 taken 349580 times.
✓ Branch 5 taken 8647166 times.
|
9346727 | if (tables_list && implicit_grouping && |
| 473 |
2/2✓ Branch 0 taken 349580 times.
✓ Branch 1 taken 401 times.
|
349981 | !(query_block->active_options() & OPTION_NO_CONST_TABLES)) { |
| 474 | aggregate_evaluated outcome; | ||
| 475 |
3/4✓ Branch 0 taken 349580 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 349568 times.
|
349580 | if (optimize_aggregated_query(thd, query_block, *fields, where_cond, |
| 476 | &outcome)) { | ||
| 477 | 12 | error = 1; | |
| 478 |
3/8✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
12 | DBUG_PRINT("error", ("Error from optimize_aggregated_query")); |
| 479 | 12 | return true; | |
| 480 | } | ||
| 481 |
4/5✓ Branch 0 taken 323115 times.
✓ Branch 1 taken 15860 times.
✓ Branch 2 taken 6082 times.
✓ Branch 3 taken 4511 times.
✗ Branch 4 not taken.
|
349568 | switch (outcome) { |
| 482 | 323115 | case AGGR_REGULAR: | |
| 483 | // Query was not (fully) evaluated. Revert to regular optimization. | ||
| 484 | 323115 | break; | |
| 485 | 15860 | case AGGR_DELAYED: | |
| 486 | // Query was not (fully) evaluated. Revert to regular optimization, | ||
| 487 | // but indicate that storage engine supports HA_COUNT_ROWS_INSTANT. | ||
| 488 | 15860 | select_count = true; | |
| 489 | 15860 | break; | |
| 490 | 6082 | case AGGR_COMPLETE: { | |
| 491 | // All SELECT expressions are fully evaluated | ||
| 492 |
3/8✓ Branch 0 taken 6082 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6082 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6082 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
6082 | DBUG_PRINT("info", ("Select tables optimized away")); |
| 493 | 6082 | zero_result_cause = "Select tables optimized away"; | |
| 494 | 6082 | tables_list = nullptr; // All tables resolved | |
| 495 | 6082 | best_rowcount = 1; | |
| 496 | 6082 | const_tables = tables = primary_tables = query_block->leaf_table_count; | |
| 497 | AccessPath *path = | ||
| 498 | 6082 | NewFakeSingleRowAccessPath(thd, /*count_examined_rows=*/true); | |
| 499 |
1/2✓ Branch 0 taken 6082 times.
✗ Branch 1 not taken.
|
6082 | path = attach_access_paths_for_having_and_limit(path); |
| 500 | 6082 | m_root_access_path = path; | |
| 501 | /* | ||
| 502 | There are no relevant conditions left from the WHERE; | ||
| 503 | optimize_aggregated_query() will not return AGGR_COMPLETE if there are | ||
| 504 | any table-independent conditions, and all other conditions have been | ||
| 505 | optimized away by it. Thus, remove the condition, unless we have | ||
| 506 | EXPLAIN (in which case we will keep it for printing). | ||
| 507 | */ | ||
| 508 |
2/2✓ Branch 0 taken 5928 times.
✓ Branch 1 taken 154 times.
|
6082 | if (!thd->lex->is_explain()) { |
| 509 | #ifndef NDEBUG | ||
| 510 | // Verify, to be sure. | ||
| 511 |
2/2✓ Branch 0 taken 3244 times.
✓ Branch 1 taken 2684 times.
|
5928 | if (where_cond != nullptr) { |
| 512 | 6488 | Item *table_independent_conds = make_cond_for_table( | |
| 513 |
1/2✓ Branch 0 taken 3244 times.
✗ Branch 1 not taken.
|
3244 | thd, where_cond, PSEUDO_TABLE_BITS, table_map(0), |
| 514 | /*exclude_expensive_cond=*/true); | ||
| 515 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3244 times.
|
3244 | assert(table_independent_conds == nullptr); |
| 516 | } | ||
| 517 | #endif | ||
| 518 | 5928 | where_cond = nullptr; | |
| 519 | } | ||
| 520 | 10593 | goto setup_subq_exit; | |
| 521 | } | ||
| 522 | 4511 | case AGGR_EMPTY: | |
| 523 | // It was detected that the result tables are empty | ||
| 524 |
3/8✓ Branch 0 taken 4511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4511 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4511 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
4511 | DBUG_PRINT("info", ("No matching min/max row")); |
| 525 | 4511 | zero_result_cause = "No matching min/max row"; | |
| 526 |
1/2✓ Branch 0 taken 4511 times.
✗ Branch 1 not taken.
|
4511 | create_access_paths_for_zero_rows(); |
| 527 | 4511 | goto setup_subq_exit; | |
| 528 | } | ||
| 529 | } | ||
| 530 |
2/2✓ Branch 0 taken 7119112 times.
✓ Branch 1 taken 1867029 times.
|
8986141 | if (tables_list == nullptr) { |
| 531 |
5/8✓ Branch 0 taken 7119120 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7119122 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 7119119 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
|
7119112 | DBUG_PRINT("info", ("No tables")); |
| 532 | 7119122 | best_rowcount = 1; | |
| 533 | 7119122 | error = 0; | |
| 534 |
3/4✓ Branch 0 taken 7119122 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 7119121 times.
|
7119122 | if (make_tmp_tables_info()) return true; |
| 535 |
1/2✓ Branch 0 taken 7119128 times.
✗ Branch 1 not taken.
|
7119121 | count_field_types(query_block, &tmp_table_param, *fields, false, false); |
| 536 | // Make plan visible for EXPLAIN | ||
| 537 |
1/2✓ Branch 0 taken 7119130 times.
✗ Branch 1 not taken.
|
7119128 | set_plan_state(NO_TABLES); |
| 538 |
1/2✓ Branch 0 taken 7119113 times.
✗ Branch 1 not taken.
|
7119130 | create_access_paths(); |
| 539 | 7119113 | return false; | |
| 540 | } | ||
| 541 | 1867029 | error = -1; // Error is sent to client | |
| 542 | |||
| 543 | { | ||
| 544 | 1867029 | m_windowing_steps = false; // initialization | |
| 545 | 1867029 | m_windows_sort = false; | |
| 546 |
1/2✓ Branch 0 taken 1867067 times.
✗ Branch 1 not taken.
|
1867029 | List_iterator<Window> li(m_windows); |
| 547 | Window *w; | ||
| 548 |
2/2✓ Branch 0 taken 2045 times.
✓ Branch 1 taken 1865703 times.
|
1867736 | while ((w = li++)) |
| 549 |
2/2✓ Branch 0 taken 1376 times.
✓ Branch 1 taken 669 times.
|
2045 | if (w->needs_sorting()) { |
| 550 | 1376 | m_windows_sort = true; | |
| 551 | 1376 | break; | |
| 552 | } | ||
| 553 | } | ||
| 554 | |||
| 555 | 3734124 | sort_by_table = get_sort_by_table(order.order, group_list.order, | |
| 556 |
1/2✓ Branch 0 taken 1867045 times.
✗ Branch 1 not taken.
|
1867079 | query_block->leaf_tables); |
| 557 | |||
| 558 |
8/8✓ Branch 0 taken 631842 times.
✓ Branch 1 taken 1235203 times.
✓ Branch 2 taken 624352 times.
✓ Branch 3 taken 7490 times.
✓ Branch 4 taken 212068 times.
✓ Branch 5 taken 412284 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 1867085 times.
|
3321849 | if ((where_cond || !group_list.empty() || !order.empty()) && |
| 559 |
3/4✓ Branch 0 taken 1454804 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1454801 times.
|
1454761 | substitute_gc(thd, query_block, where_cond, group_list.order, |
| 560 | order.order)) { | ||
| 561 | // We added hidden fields to the all_fields list, count them. | ||
| 562 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | count_field_types(query_block, &tmp_table_param, query_block->fields, false, |
| 563 | false); | ||
| 564 | } | ||
| 565 | // Ensure there are no errors prior making query plan | ||
| 566 |
3/4✓ Branch 0 taken 1867090 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1867088 times.
|
1867088 | if (thd->is_error()) return true; |
| 567 | |||
| 568 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 1866992 times.
|
1867088 | if (thd->lex->using_hypergraph_optimizer) { |
| 569 |
1/2✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
|
96 | Item *where_cond_no_in2exists = remove_in2exists_conds(thd, where_cond); |
| 570 |
1/2✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
|
96 | Item *having_cond_no_in2exists = remove_in2exists_conds(thd, having_cond); |
| 571 | |||
| 572 | 96 | std::string trace_str; | |
| 573 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 56 times.
|
96 | std::string *trace_ptr = thd->opt_trace.is_started() ? &trace_str : nullptr; |
| 574 | |||
| 575 |
1/2✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
|
96 | SaveCondEqualLists(cond_equal); |
| 576 | |||
| 577 |
1/2✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
|
96 | m_root_access_path = FindBestQueryPlan(thd, query_block, trace_ptr); |
| 578 |
3/4✓ Branch 0 taken 76 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
|
96 | if (finalize_access_paths && m_root_access_path != nullptr) { |
| 579 |
2/4✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 76 times.
|
76 | if (FinalizePlanForQueryBlock(thd, query_block)) { |
| 580 | ✗ | return true; | |
| 581 | } | ||
| 582 | } | ||
| 583 | |||
| 584 | // If this query block was modified by IN-to-EXISTS conversion, | ||
| 585 | // the outer query block may want to undo that conversion and materialize | ||
| 586 | // us instead, depending on cost. (Materialization has high initial cost, | ||
| 587 | // but looking up in the materialized table is typically cheaper than | ||
| 588 | // running the entire query.) If so, we will need to plan the query again, | ||
| 589 | // but with all extra conditions added by IN-to-EXISTS removed, as those | ||
| 590 | // are specific to the values referred to by the outer query. | ||
| 591 | // | ||
| 592 | // Thus, we detect this here, and plan a second query plan. There are | ||
| 593 | // computations that could be shared between the two plans (e.g. join order | ||
| 594 | // between tables for which there is no IN-to-EXISTS-related condition), | ||
| 595 | // so it is somewhat wasteful, but experiments have shown that planning | ||
| 596 | // both at the same time quickly clutters the code with such handling; | ||
| 597 | // there are so many places such filters could be added (base table filters, | ||
| 598 | // filters after various types of joins, join conditions, post-join filters, | ||
| 599 | // HAVING, possibly others) that trying to plan paths both with and without | ||
| 600 | // them incurs complexity that is not justified by the small computational | ||
| 601 | // gain it would bring. | ||
| 602 |
2/2✓ Branch 0 taken 95 times.
✓ Branch 1 taken 1 times.
|
96 | if (where_cond != where_cond_no_in2exists || |
| 603 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 88 times.
|
95 | having_cond != having_cond_no_in2exists) { |
| 604 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
|
8 | if (trace_ptr != nullptr) { |
| 605 | *trace_ptr += | ||
| 606 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | "\nPlanning an alternative with in2exists conditions removed:\n"; |
| 607 | } | ||
| 608 | 8 | where_cond = where_cond_no_in2exists; | |
| 609 | 8 | having_cond = having_cond_no_in2exists; | |
| 610 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | assert(!finalize_access_paths); |
| 611 | 8 | m_root_access_path_no_in2exists = | |
| 612 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | FindBestQueryPlan(thd, query_block, trace_ptr); |
| 613 | } else { | ||
| 614 | 88 | m_root_access_path_no_in2exists = nullptr; | |
| 615 | } | ||
| 616 | |||
| 617 |
1/2✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
|
96 | if (trace != nullptr) { |
| 618 |
1/2✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
|
96 | Opt_trace_object trace_wrapper2(&thd->opt_trace); |
| 619 |
1/2✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
|
96 | Opt_trace_array join_optimizer(&thd->opt_trace, "join_optimizer"); |
| 620 | |||
| 621 | // Split by newlines. | ||
| 622 |
2/2✓ Branch 0 taken 2183 times.
✓ Branch 1 taken 96 times.
|
2279 | for (size_t pos = 0; pos < trace_str.size();) { |
| 623 | 2183 | size_t len = strcspn(trace_str.data() + pos, "\n"); | |
| 624 |
1/2✓ Branch 0 taken 2183 times.
✗ Branch 1 not taken.
|
2183 | join_optimizer.add_utf8(trace_str.data() + pos, len); |
| 625 | 2183 | pos += len + 1; | |
| 626 | } | ||
| 627 | 96 | } | |
| 628 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
|
96 | if (m_root_access_path == nullptr) { |
| 629 | ✗ | return true; | |
| 630 | } | ||
| 631 |
1/2✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
|
96 | set_plan_state(PLAN_READY); |
| 632 |
2/4✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 96 times.
✗ Branch 3 not taken.
|
96 | DEBUG_SYNC(thd, "after_join_optimize"); |
| 633 | 96 | return false; | |
| 634 | 96 | } | |
| 635 | |||
| 636 | // ---------------------------------------------------------------------------- | ||
| 637 | // All of this is never called for the hypergraph join optimizer! | ||
| 638 | // ---------------------------------------------------------------------------- | ||
| 639 | |||
| 640 | // Set up join order and initial access paths | ||
| 641 |
1/2✓ Branch 0 taken 1866983 times.
✗ Branch 1 not taken.
|
1866992 | THD_STAGE_INFO(thd, stage_statistics); |
| 642 |
3/4✓ Branch 0 taken 1866980 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 1866872 times.
|
1866983 | if (make_join_plan()) { |
| 643 |
3/4✓ Branch 0 taken 10 times.
✓ Branch 1 taken 98 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
108 | if (thd->killed) thd->send_kill_message(); |
| 644 |
3/8✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 108 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 108 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
108 | DBUG_PRINT("error", ("Error: JOIN::make_join_plan() failed")); |
| 645 | 108 | return true; | |
| 646 | } | ||
| 647 | |||
| 648 | // At this stage, join_tab==NULL, JOIN_TABs are listed in order by best_ref. | ||
| 649 |
4/6✓ Branch 0 taken 1866815 times.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 1866821 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1866846 times.
✗ Branch 5 not taken.
|
1866872 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 650 | |||
| 651 |
2/2✓ Branch 0 taken 50239 times.
✓ Branch 1 taken 1816664 times.
|
1866903 | if (zero_result_cause != nullptr) { // Can be set by make_join_plan(). |
| 652 |
1/2✓ Branch 0 taken 50239 times.
✗ Branch 1 not taken.
|
50239 | create_access_paths_for_zero_rows(); |
| 653 | 50239 | goto setup_subq_exit; | |
| 654 | } | ||
| 655 | |||
| 656 |
2/2✓ Branch 0 taken 1816205 times.
✓ Branch 1 taken 459 times.
|
1816664 | if (rollup_state == RollupState::NONE) { |
| 657 | /* Remove distinct if only const tables */ | ||
| 658 | 1816205 | select_distinct &= !plan_is_const(); | |
| 659 | } | ||
| 660 | |||
| 661 |
6/6✓ Branch 0 taken 87134 times.
✓ Branch 1 taken 1729569 times.
✓ Branch 2 taken 82516 times.
✓ Branch 3 taken 4618 times.
✓ Branch 4 taken 80393 times.
✓ Branch 5 taken 1736310 times.
|
1899219 | if (const_tables && !thd->locked_tables_mode && |
| 662 |
2/2✓ Branch 0 taken 80393 times.
✓ Branch 1 taken 2123 times.
|
82516 | !(query_block->active_options() & SELECT_NO_UNLOCK)) { |
| 663 | TABLE *ct[MAX_TABLES]; | ||
| 664 |
2/2✓ Branch 0 taken 83123 times.
✓ Branch 1 taken 80393 times.
|
163516 | for (uint i = 0; i < const_tables; i++) { |
| 665 | 83123 | ct[i] = best_ref[i]->table(); | |
| 666 |
1/2✓ Branch 0 taken 83123 times.
✗ Branch 1 not taken.
|
83123 | ct[i]->file->ha_index_or_rnd_end(); |
| 667 | } | ||
| 668 |
1/2✓ Branch 0 taken 80393 times.
✗ Branch 1 not taken.
|
80393 | mysql_unlock_some_tables(thd, ct, const_tables); |
| 669 | } | ||
| 670 |
4/4✓ Branch 0 taken 630493 times.
✓ Branch 1 taken 1186210 times.
✓ Branch 2 taken 5741 times.
✓ Branch 3 taken 624752 times.
|
1816703 | if (!where_cond && query_block->outer_join) { |
| 671 | /* Handle the case where we have an OUTER JOIN without a WHERE */ | ||
| 672 |
1/2✓ Branch 0 taken 5741 times.
✗ Branch 1 not taken.
|
11482 | where_cond = new Item_func_true(); // Always true |
| 673 | } | ||
| 674 | |||
| 675 | 1816703 | error = 0; | |
| 676 | /* | ||
| 677 | Among the equal fields belonging to the same multiple equality | ||
| 678 | choose the one that is to be retrieved first and substitute | ||
| 679 | all references to these in where condition for a reference for | ||
| 680 | the selected field. | ||
| 681 | */ | ||
| 682 |
2/2✓ Branch 0 taken 1191797 times.
✓ Branch 1 taken 624906 times.
|
1816703 | if (where_cond) { |
| 683 | 1191885 | where_cond = | |
| 684 |
1/2✓ Branch 0 taken 1191885 times.
✗ Branch 1 not taken.
|
1191797 | substitute_for_best_equal_field(thd, where_cond, cond_equal, map2table); |
| 685 |
2/4✓ Branch 0 taken 1191888 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1191888 times.
|
1191885 | if (thd->is_error()) { |
| 686 | ✗ | error = 1; | |
| 687 | ✗ | DBUG_PRINT("error", ("Error from substitute_for_best_equal")); | |
| 688 | ✗ | return true; | |
| 689 | } | ||
| 690 |
1/2✓ Branch 0 taken 1191890 times.
✗ Branch 1 not taken.
|
1191888 | where_cond->update_used_tables(); |
| 691 |
3/6✓ Branch 0 taken 1191888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 1191881 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1191890 | DBUG_EXECUTE("where", |
| 692 | print_where(thd, where_cond, "after substitute_best_equal", | ||
| 693 | QT_ORDINARY);); | ||
| 694 | } | ||
| 695 | |||
| 696 | /* | ||
| 697 | Perform the same optimization on field evaluation for all join conditions. | ||
| 698 | */ | ||
| 699 |
2/2✓ Branch 0 taken 6167448 times.
✓ Branch 1 taken 1816595 times.
|
7984043 | for (uint i = const_tables; i < tables; ++i) { |
| 700 | 6167448 | JOIN_TAB *const tab = best_ref[i]; | |
| 701 |
6/6✓ Branch 0 taken 3779777 times.
✓ Branch 1 taken 2387740 times.
✓ Branch 2 taken 530067 times.
✓ Branch 3 taken 3249749 times.
✓ Branch 4 taken 530075 times.
✓ Branch 5 taken 5637481 times.
|
6167448 | if (tab->position() && tab->join_cond()) { |
| 702 | 1060114 | tab->set_join_cond(substitute_for_best_equal_field( | |
| 703 |
1/2✓ Branch 0 taken 530039 times.
✗ Branch 1 not taken.
|
530067 | thd, tab->join_cond(), tab->cond_equal, map2table)); |
| 704 |
2/4✓ Branch 0 taken 530070 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 530070 times.
|
530035 | if (thd->is_error()) { |
| 705 | ✗ | error = 1; | |
| 706 | ✗ | DBUG_PRINT("error", ("Error from substitute_for_best_equal")); | |
| 707 | ✗ | return true; | |
| 708 | } | ||
| 709 |
1/2✓ Branch 0 taken 530079 times.
✗ Branch 1 not taken.
|
530070 | tab->join_cond()->update_used_tables(); |
| 710 |
2/2✓ Branch 0 taken 530078 times.
✓ Branch 1 taken 1 times.
|
530079 | if (tab->join_cond()) |
| 711 |
1/2✓ Branch 0 taken 529919 times.
✗ Branch 1 not taken.
|
530078 | tab->join_cond()->walk(&Item::cast_incompatible_args, |
| 712 | enum_walk::POSTFIX, nullptr); | ||
| 713 | } | ||
| 714 | } | ||
| 715 | |||
| 716 |
3/4✓ Branch 0 taken 1816642 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1816639 times.
|
1816595 | if (init_ref_access()) { |
| 717 | 3 | error = 1; | |
| 718 |
3/8✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
3 | DBUG_PRINT("error", ("Error from init_ref_access")); |
| 719 | 3 | return true; | |
| 720 | } | ||
| 721 | |||
| 722 | // Update table dependencies after assigning ref access fields | ||
| 723 |
1/2✓ Branch 0 taken 1816635 times.
✗ Branch 1 not taken.
|
1816639 | update_depend_map(); |
| 724 | |||
| 725 |
1/2✓ Branch 0 taken 1816630 times.
✗ Branch 1 not taken.
|
1816635 | THD_STAGE_INFO(thd, stage_preparing); |
| 726 | |||
| 727 |
3/4✓ Branch 0 taken 1816601 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2011 times.
✓ Branch 3 taken 1814590 times.
|
1816630 | if (make_join_query_block(this, where_cond)) { |
| 728 |
3/4✓ Branch 0 taken 2011 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2009 times.
|
2011 | if (thd->is_error()) return true; |
| 729 | |||
| 730 | 2009 | zero_result_cause = "Impossible WHERE noticed after reading const tables"; | |
| 731 |
1/2✓ Branch 0 taken 2009 times.
✗ Branch 1 not taken.
|
2009 | create_access_paths_for_zero_rows(); |
| 732 | 2009 | goto setup_subq_exit; | |
| 733 | } | ||
| 734 | |||
| 735 | // Inject cast nodes into the WHERE conditions | ||
| 736 |
2/2✓ Branch 0 taken 1113359 times.
✓ Branch 1 taken 701231 times.
|
1814590 | if (where_cond) |
| 737 |
1/2✓ Branch 0 taken 1113389 times.
✗ Branch 1 not taken.
|
1113359 | where_cond->walk(&Item::cast_incompatible_args, enum_walk::POSTFIX, |
| 738 | nullptr); | ||
| 739 | |||
| 740 | 1814620 | error = -1; /* if goto err */ | |
| 741 | |||
| 742 |
3/4✓ Branch 0 taken 1814628 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 1814582 times.
|
1814620 | if (optimize_distinct_group_order()) return true; |
| 743 | |||
| 744 |
4/4✓ Branch 0 taken 1794451 times.
✓ Branch 1 taken 20123 times.
✓ Branch 2 taken 22458 times.
✓ Branch 3 taken 1792116 times.
|
3609033 | if ((query_block->active_options() & SELECT_NO_JOIN_CACHE) || |
| 745 |
2/2✓ Branch 0 taken 2334 times.
✓ Branch 1 taken 1792117 times.
|
1794451 | query_block->ftfunc_list->elements) |
| 746 | 22458 | no_jbuf_after = 0; | |
| 747 | |||
| 748 | /* Perform FULLTEXT search before all regular searches */ | ||
| 749 |
7/8✓ Branch 0 taken 2351 times.
✓ Branch 1 taken 1812216 times.
✓ Branch 2 taken 2335 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 2332 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 1814548 times.
|
1814574 | if (query_block->has_ft_funcs() && optimize_fts_query()) return true; |
| 750 | |||
| 751 | /* | ||
| 752 | By setting child_subquery_can_materialize so late we gain the following: | ||
| 753 | JOIN::compare_costs_of_subquery_strategies() can test this variable to | ||
| 754 | know if we are have finished evaluating constant conditions, which itself | ||
| 755 | helps determining fanouts. | ||
| 756 | */ | ||
| 757 | 1814548 | child_subquery_can_materialize = true; | |
| 758 | |||
| 759 | /* | ||
| 760 | It's necessary to check const part of HAVING cond as | ||
| 761 | there is a chance that some cond parts may become | ||
| 762 | const items after make_join_plan() (for example | ||
| 763 | when Item is a reference to const table field from | ||
| 764 | outer join). | ||
| 765 | This check is performed only for those conditions | ||
| 766 | which do not use aggregate functions. In such case | ||
| 767 | temporary table may not be used and const condition | ||
| 768 | elements may be lost during further having | ||
| 769 | condition transformation in JOIN::exec. | ||
| 770 | */ | ||
| 771 |
8/8✓ Branch 0 taken 8581 times.
✓ Branch 1 taken 1805967 times.
✓ Branch 2 taken 4778 times.
✓ Branch 3 taken 3803 times.
✓ Branch 4 taken 55 times.
✓ Branch 5 taken 4723 times.
✓ Branch 6 taken 55 times.
✓ Branch 7 taken 1814493 times.
|
1814548 | if (having_cond && !having_cond->has_aggregation() && (const_tables > 0)) { |
| 772 |
1/2✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
|
55 | having_cond->update_used_tables(); |
| 773 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | if (remove_eq_conds(thd, having_cond, &having_cond, |
| 774 |
1/2✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
|
55 | &query_block->having_value)) { |
| 775 | ✗ | error = 1; | |
| 776 | ✗ | DBUG_PRINT("error", ("Error from remove_eq_conds")); | |
| 777 | ✗ | return true; | |
| 778 | } | ||
| 779 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 50 times.
|
55 | if (query_block->having_value == Item::COND_FALSE) { |
| 780 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
10 | having_cond = new Item_func_false(); |
| 781 | 5 | zero_result_cause = | |
| 782 | "Impossible HAVING noticed after reading const tables"; | ||
| 783 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | create_access_paths_for_zero_rows(); |
| 784 | 5 | goto setup_subq_exit; | |
| 785 | } | ||
| 786 | } | ||
| 787 | |||
| 788 | // Inject cast nodes into the HAVING conditions | ||
| 789 |
2/2✓ Branch 0 taken 8553 times.
✓ Branch 1 taken 1805990 times.
|
1814543 | if (having_cond) |
| 790 |
1/2✓ Branch 0 taken 8553 times.
✗ Branch 1 not taken.
|
8553 | having_cond->walk(&Item::cast_incompatible_args, enum_walk::POSTFIX, |
| 791 | nullptr); | ||
| 792 | |||
| 793 | // Traverse the expressions and inject cast nodes to compatible data types, | ||
| 794 | // if needed. | ||
| 795 |
7/12✓ Branch 0 taken 1814478 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1814542 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8087588 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8087579 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9902133 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 8087548 times.
✓ Branch 11 taken 1814585 times.
|
9902145 | for (Item *item : *fields) { |
| 796 |
1/2✓ Branch 0 taken 8087602 times.
✗ Branch 1 not taken.
|
8087588 | item->walk(&Item::cast_incompatible_args, enum_walk::POSTFIX, nullptr); |
| 797 | } | ||
| 798 | |||
| 799 | // Also GROUP BY expressions, so that find_in_group_list() doesn't | ||
| 800 | // inadvertently fail because the SELECT list has casts that GROUP BY doesn't. | ||
| 801 |
2/2✓ Branch 0 taken 23563 times.
✓ Branch 1 taken 1814585 times.
|
1838148 | for (ORDER *ord = group_list.order; ord != nullptr; ord = ord->next) { |
| 802 | 23563 | (*ord->item) | |
| 803 |
1/2✓ Branch 0 taken 23563 times.
✗ Branch 1 not taken.
|
23563 | ->walk(&Item::cast_incompatible_args, enum_walk::POSTFIX, nullptr); |
| 804 | } | ||
| 805 | |||
| 806 |
2/2✓ Branch 0 taken 374 times.
✓ Branch 1 taken 1814211 times.
|
1814585 | if (rollup_state != RollupState::NONE) { |
| 807 | /* | ||
| 808 | Fields may have been replaced by Item_rollup_group_item, so | ||
| 809 | recalculate the number of fields and functions for this query block. | ||
| 810 | */ | ||
| 811 | |||
| 812 | // JOIN::optimize_rollup() may set allow_group_via_temp_table = false, | ||
| 813 | // and we must not undo that. | ||
| 814 | 374 | const bool save_allow_group_via_temp_table = | |
| 815 | tmp_table_param.allow_group_via_temp_table; | ||
| 816 | |||
| 817 |
1/2✓ Branch 0 taken 374 times.
✗ Branch 1 not taken.
|
374 | count_field_types(query_block, &tmp_table_param, *fields, false, false); |
| 818 | 374 | tmp_table_param.allow_group_via_temp_table = | |
| 819 | save_allow_group_via_temp_table; | ||
| 820 | } | ||
| 821 | |||
| 822 | // See if this subquery can be evaluated with subselect_indexsubquery_engine | ||
| 823 |
3/4✓ Branch 0 taken 1814565 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1216 times.
✓ Branch 3 taken 1813349 times.
|
1814585 | if (const int ret = replace_index_subquery()) { |
| 824 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1216 times.
|
1216 | if (ret == -1) { |
| 825 | // Error (e.g. allocation failed, or some condition was attempted | ||
| 826 | // evaluated statically and failed). | ||
| 827 | ✗ | return true; | |
| 828 | } | ||
| 829 | |||
| 830 |
1/2✓ Branch 0 taken 1216 times.
✗ Branch 1 not taken.
|
1216 | create_access_paths_for_index_subquery(); |
| 831 |
1/2✓ Branch 0 taken 1216 times.
✗ Branch 1 not taken.
|
1216 | set_plan_state(PLAN_READY); |
| 832 | /* | ||
| 833 | We leave optimize() because the rest of it is only about order/group | ||
| 834 | which those subqueries don't have and about setting up plan which | ||
| 835 | we're not going to use due to different execution method. | ||
| 836 | */ | ||
| 837 | 1216 | return false; | |
| 838 | } | ||
| 839 | |||
| 840 | { | ||
| 841 | /* | ||
| 842 | If the hint FORCE INDEX FOR ORDER BY/GROUP BY is used for the first | ||
| 843 | table (it does not make sense for other tables) then we cannot do join | ||
| 844 | buffering. | ||
| 845 | */ | ||
| 846 |
2/2✓ Branch 0 taken 1730947 times.
✓ Branch 1 taken 82404 times.
|
1813349 | if (!plan_is_const()) { |
| 847 | 1730947 | const TABLE *const first = best_ref[const_tables]->table(); | |
| 848 |
6/6✓ Branch 0 taken 1782 times.
✓ Branch 1 taken 1729150 times.
✓ Branch 2 taken 1563 times.
✓ Branch 3 taken 220 times.
✓ Branch 4 taken 232 times.
✓ Branch 5 taken 1730701 times.
|
3461645 | if ((first->force_index_order && !order.empty()) || |
| 849 |
4/4✓ Branch 0 taken 1569 times.
✓ Branch 1 taken 1729144 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 1557 times.
|
1730713 | (first->force_index_group && !group_list.empty())) |
| 850 | 232 | no_jbuf_after = 0; | |
| 851 | } | ||
| 852 | |||
| 853 | 1813337 | bool simple_sort = true; | |
| 854 | 1813337 | Table_map_restorer deps_lateral(&deps_of_remaining_lateral_derived_tables); | |
| 855 | // Check whether join cache could be used | ||
| 856 |
2/2✓ Branch 0 taken 6162503 times.
✓ Branch 1 taken 1813487 times.
|
7975990 | for (uint i = const_tables; i < tables; i++) { |
| 857 | 6162503 | JOIN_TAB *const tab = best_ref[i]; | |
| 858 |
2/2✓ Branch 0 taken 2384142 times.
✓ Branch 1 taken 3778469 times.
|
6162503 | if (!tab->position()) continue; |
| 859 |
2/4✓ Branch 0 taken 3778399 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3778399 times.
|
3778469 | if (setup_join_buffering(tab, this, no_jbuf_after)) return true; |
| 860 |
2/2✓ Branch 0 taken 131714 times.
✓ Branch 1 taken 3646770 times.
|
3778399 | if (tab->use_join_cache() != JOIN_CACHE::ALG_NONE) simple_sort = false; |
| 861 |
3/4✓ Branch 0 taken 2167 times.
✓ Branch 1 taken 3776330 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2200 times.
|
3778484 | assert(tab->type() != JT_FT || |
| 862 | tab->use_join_cache() == JOIN_CACHE::ALG_NONE); | ||
| 863 |
6/6✓ Branch 0 taken 2116 times.
✓ Branch 1 taken 3776414 times.
✓ Branch 2 taken 562 times.
✓ Branch 3 taken 1554 times.
✓ Branch 4 taken 562 times.
✓ Branch 5 taken 3777968 times.
|
3778530 | if (has_lateral && get_lateral_deps(*best_ref[i]) != 0) { |
| 864 | 562 | deps_of_remaining_lateral_derived_tables = | |
| 865 |
1/2✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
|
562 | calculate_deps_of_remaining_lateral_derived_tables(all_table_map, |
| 866 | i + 1); | ||
| 867 | } | ||
| 868 | } | ||
| 869 |
2/2✓ Branch 0 taken 108430 times.
✓ Branch 1 taken 1705057 times.
|
1813487 | if (!simple_sort) { |
| 870 | /* | ||
| 871 | A join buffer is used for this table. We here inform the optimizer | ||
| 872 | that it should not rely on rows of the first non-const table being in | ||
| 873 | order thanks to an index scan; indeed join buffering of the present | ||
| 874 | table subsequently changes the order of rows. | ||
| 875 | */ | ||
| 876 | 108430 | simple_order = simple_group = false; | |
| 877 | } | ||
| 878 |
1/2✓ Branch 0 taken 1813358 times.
✗ Branch 1 not taken.
|
1813487 | } |
| 879 | |||
| 880 |
6/6✓ Branch 0 taken 1730983 times.
✓ Branch 1 taken 82376 times.
✓ Branch 2 taken 542026 times.
✓ Branch 3 taken 1188957 times.
✓ Branch 4 taken 542026 times.
✓ Branch 5 taken 1271333 times.
|
1813358 | if (!plan_is_const() && !order.empty()) { |
| 881 | /* | ||
| 882 | Force using of tmp table if sorting by a SP or UDF function due to | ||
| 883 | their expensive and probably non-deterministic nature. | ||
| 884 | */ | ||
| 885 |
2/2✓ Branch 0 taken 848994 times.
✓ Branch 1 taken 541976 times.
|
1390970 | for (ORDER *tmp_order = order.order; tmp_order; |
| 886 | 848944 | tmp_order = tmp_order->next) { | |
| 887 | 848994 | Item *item = *tmp_order->item; | |
| 888 |
3/4✓ Branch 0 taken 848994 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 848944 times.
|
848994 | if (item->is_expensive()) { |
| 889 | /* Force tmp table without sort */ | ||
| 890 | 50 | simple_order = simple_group = false; | |
| 891 | 50 | break; | |
| 892 | } | ||
| 893 | } | ||
| 894 | } | ||
| 895 | |||
| 896 | /* | ||
| 897 | Check if we need to create a temporary table prior to any windowing. | ||
| 898 | |||
| 899 | (1) If there is ROLLUP, which happens before DISTINCT, windowing and ORDER | ||
| 900 | BY, any of those clauses needs the result of ROLLUP in a tmp table. | ||
| 901 | |||
| 902 | Rows which ROLLUP adds to the result are visible only to DISTINCT, | ||
| 903 | windowing and ORDER BY which we handled above. So for the rest of | ||
| 904 | conditions ((2), etc), we can do as if there were no ROLLUP. | ||
| 905 | |||
| 906 | (2) If all tables are constant, the query's result is guaranteed to have 0 | ||
| 907 | or 1 row only, so all SQL clauses discussed below (DISTINCT, ORDER BY, | ||
| 908 | GROUP BY, windowing, SQL_BUFFER_RESULT) are useless and need no tmp | ||
| 909 | table. | ||
| 910 | |||
| 911 | (3) If there is GROUP BY which isn't resolved by using an index or sorting | ||
| 912 | the first table, we need a tmp table to compute the grouped rows. | ||
| 913 | GROUP BY happens before windowing; so it is a pre-windowing tmp | ||
| 914 | table. | ||
| 915 | |||
| 916 | (4) (5) If there is DISTINCT, or ORDER BY which isn't resolved by using an | ||
| 917 | index or sorting the first table, those clauses need an input tmp table. | ||
| 918 | If we have windowing, as those clauses are used after windowing, they can | ||
| 919 | use the last window's tmp table. | ||
| 920 | |||
| 921 | (6) If there are different ORDER BY and GROUP BY orders, ORDER BY needs an | ||
| 922 | input tmp table, so it's like (5). | ||
| 923 | |||
| 924 | (7) If the user wants us to buffer the result, we need a tmp table. But | ||
| 925 | windowing creates one anyway, and so does the materialization of a derived | ||
| 926 | table. | ||
| 927 | |||
| 928 | See also the computation of Window::m_short_circuit, | ||
| 929 | where we make sure to create a tmp table if the clauses above want one. | ||
| 930 | |||
| 931 | (8) If the first windowing step needs sorting, filesort() will be used; it | ||
| 932 | can sort one table but not a join of tables, so we need a tmp table | ||
| 933 | then. If GROUP BY was optimized away, the pre-windowing result is 0 or 1 | ||
| 934 | row so doesn't need sorting. | ||
| 935 | */ | ||
| 936 | |||
| 937 |
4/4✓ Branch 0 taken 374 times.
✓ Branch 1 taken 1812985 times.
✓ Branch 2 taken 127 times.
✓ Branch 3 taken 1813232 times.
|
1813733 | if (rollup_state != RollupState::NONE && // (1) |
| 938 |
6/6✓ Branch 0 taken 334 times.
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 287 times.
✓ Branch 3 taken 47 times.
✓ Branch 4 taken 40 times.
✓ Branch 5 taken 247 times.
|
374 | (select_distinct || has_windows || !order.empty())) |
| 939 | 127 | need_tmp_before_win = true; | |
| 940 | |||
| 941 | /* | ||
| 942 | If we have full-text columns involved in aggregation, we need to | ||
| 943 | materialize it, as the saving and loading of rows in AggregateIterator | ||
| 944 | does not include FTS information. If we have multiple tables, we'll | ||
| 945 | have a materialization (either because we're aggregating into a temporary | ||
| 946 | table, or because we always materialize before further operations), | ||
| 947 | and if we have a GROUP BY, we'll either have an aggregate-to-table | ||
| 948 | or a sort, which also fixes the issue. However, in the case of a single | ||
| 949 | table and implicit grouping, we need to force the temporary table here. | ||
| 950 | */ | ||
| 951 |
2/2✓ Branch 0 taken 337076 times.
✓ Branch 1 taken 1476065 times.
|
1813141 | if (!need_tmp_before_win && implicit_grouping && |
| 952 |
9/10✓ Branch 0 taken 1813141 times.
✓ Branch 1 taken 218 times.
✓ Branch 2 taken 289567 times.
✓ Branch 3 taken 47509 times.
✓ Branch 4 taken 289672 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 88 times.
✓ Branch 7 taken 289479 times.
✓ Branch 8 taken 88 times.
✓ Branch 9 taken 1813166 times.
|
3916067 | primary_tables - const_tables == 1 && order.empty() && |
| 953 | 289672 | best_ref[const_tables]->table_ref->is_fulltext_searched()) { | |
| 954 |
8/14✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 88 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 88 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 86 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 174 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 88 times.
✓ Branch 13 taken 86 times.
|
174 | for (Item *item : VisibleFields(*fields)) { |
| 955 | 88 | need_tmp_before_win |= | |
| 956 |
1/2✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
|
88 | contains_function_of_type(item, Item_func::FT_FUNC); |
| 957 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 86 times.
|
88 | if (need_tmp_before_win) break; |
| 958 | } | ||
| 959 | } | ||
| 960 | |||
| 961 |
2/2✓ Branch 0 taken 1730929 times.
✓ Branch 1 taken 82352 times.
|
1813254 | if (!plan_is_const()) // (2) |
| 962 | { | ||
| 963 |
2/2✓ Branch 0 taken 14341 times.
✓ Branch 1 taken 1795 times.
|
1747065 | if ((!group_list.empty() && !simple_group) || // (3) |
| 964 |
4/4✓ Branch 0 taken 1727530 times.
✓ Branch 1 taken 1628 times.
✓ Branch 2 taken 1726486 times.
✓ Branch 3 taken 1044 times.
|
1729158 | (!has_windows && (select_distinct || // (4) |
| 965 |
4/4✓ Branch 0 taken 541057 times.
✓ Branch 1 taken 1185419 times.
✓ Branch 2 taken 299515 times.
✓ Branch 3 taken 241542 times.
|
1726486 | (!order.empty() && !simple_order) || // (5) |
| 966 |
4/4✓ Branch 0 taken 13968 times.
✓ Branch 1 taken 1470941 times.
✓ Branch 2 taken 13851 times.
✓ Branch 3 taken 117 times.
|
1484934 | (!group_list.empty() && !order.empty()))) || // (6) |
| 967 |
2/2✓ Branch 0 taken 5568 times.
✓ Branch 1 taken 1480804 times.
|
1486420 | ((query_block->active_options() & OPTION_BUFFER_RESULT) && |
| 968 |
2/2✓ Branch 0 taken 5566 times.
✓ Branch 1 taken 2 times.
|
5568 | !has_windows && |
| 969 |
2/2✓ Branch 0 taken 66 times.
✓ Branch 1 taken 5500 times.
|
5566 | !(query_expression()->derived_table && |
| 970 | 66 | query_expression() | |
| 971 |
8/8✓ Branch 0 taken 16136 times.
✓ Branch 1 taken 1714817 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 48 times.
✓ Branch 4 taken 1625 times.
✓ Branch 5 taken 1479199 times.
✓ Branch 6 taken 250084 times.
✓ Branch 7 taken 1480786 times.
|
3463448 | ->derived_table->uses_materialization())) || // (7) |
| 972 |
4/4✓ Branch 0 taken 52 times.
✓ Branch 1 taken 1573 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 19 times.
|
1677 | (has_windows && (primary_tables - const_tables) > 1 && // (8) |
| 973 |
1/2✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
|
85 | m_windows[0]->needs_sorting() && !group_optimized_away)) |
| 974 | 250084 | need_tmp_before_win = true; | |
| 975 | } | ||
| 976 | |||
| 977 |
4/6✓ Branch 0 taken 1813324 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 1813296 times.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
1813222 | DBUG_EXECUTE("info", TEST_join(this);); |
| 978 | |||
| 979 |
2/4✓ Branch 0 taken 1813353 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1813353 times.
|
1813324 | if (alloc_qep(tables)) return (error = 1); /* purecov: inspected */ |
| 980 | |||
| 981 |
2/2✓ Branch 0 taken 1730978 times.
✓ Branch 1 taken 82378 times.
|
1813353 | if (!plan_is_const()) { |
| 982 | // Test if we can use an index instead of sorting | ||
| 983 |
1/2✓ Branch 0 taken 1730976 times.
✗ Branch 1 not taken.
|
1730978 | test_skip_sort(); |
| 984 | |||
| 985 |
3/4✓ Branch 0 taken 1730929 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1730928 times.
|
1730976 | if (finalize_table_conditions()) return true; |
| 986 | } | ||
| 987 | |||
| 988 |
3/4✓ Branch 0 taken 1813362 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1813361 times.
|
1813306 | if (make_join_readinfo(this, no_jbuf_after)) |
| 989 | 1 | return true; /* purecov: inspected */ | |
| 990 | |||
| 991 |
3/4✓ Branch 0 taken 1813352 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1813351 times.
|
1813361 | if (make_tmp_tables_info()) return true; |
| 992 | |||
| 993 | /* | ||
| 994 | If we decided to not sort after all, update the cost of the JOIN. | ||
| 995 | Windowing sorts are handled elsewhere | ||
| 996 | */ | ||
| 997 |
4/4✓ Branch 0 taken 380682 times.
✓ Branch 1 taken 1432669 times.
✓ Branch 2 taken 22534 times.
✓ Branch 3 taken 1790817 times.
|
2194033 | if (sort_cost > 0.0 && |
| 998 |
2/2✓ Branch 0 taken 22534 times.
✓ Branch 1 taken 358148 times.
|
380682 | !explain_flags.any(ESP_USING_FILESORT, ESC_WINDOWING)) { |
| 999 | 22534 | best_read -= sort_cost; | |
| 1000 | 22534 | sort_cost = 0.0; | |
| 1001 | } | ||
| 1002 | |||
| 1003 |
1/2✓ Branch 0 taken 1813351 times.
✗ Branch 1 not taken.
|
1813351 | count_field_types(query_block, &tmp_table_param, *fields, false, false); |
| 1004 | |||
| 1005 |
1/2✓ Branch 0 taken 1813265 times.
✗ Branch 1 not taken.
|
1813351 | create_access_paths(); |
| 1006 | |||
| 1007 | // Creating iterators may evaluate a constant hash join condition, which may | ||
| 1008 | // fail: | ||
| 1009 |
2/4✓ Branch 0 taken 1813325 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1813325 times.
|
1813265 | if (thd->is_error()) return true; |
| 1010 | |||
| 1011 | /* | ||
| 1012 | At this stage, we have set up an AccessPath 'plan'. Traverse the | ||
| 1013 | AccessPath structures and find components which may be offloaded to | ||
| 1014 | the engines. This process is allowed to modify the AccessPath itself. | ||
| 1015 | (Removing/modifying FILTERs where pushed to the engines, change JOIN* | ||
| 1016 | algorithms being used, modify aggregate expressions, ...). | ||
| 1017 | This will later affects which type of Iterator we should create. Thus no | ||
| 1018 | Iterators should be set up until after push_to_engines() has completed. | ||
| 1019 | |||
| 1020 | Note that when the Hypergraph optimizer is used, there is an entirely | ||
| 1021 | different code path to push_to_engine(). (We create the AcccesPath directly | ||
| 1022 | instead of converting the QEP_TABs into an AccessPath structure). | ||
| 1023 | In the HG case we push_to_engine() when FinalizePlanForQueryBlock() | ||
| 1024 | has finalized the 'plan'. | ||
| 1025 | */ | ||
| 1026 |
2/4✓ Branch 0 taken 1813346 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1813346 times.
|
1813325 | if (push_to_engines()) return true; |
| 1027 | |||
| 1028 | // Make plan visible for EXPLAIN | ||
| 1029 |
1/2✓ Branch 0 taken 1813356 times.
✗ Branch 1 not taken.
|
1813346 | set_plan_state(PLAN_READY); |
| 1030 | |||
| 1031 |
3/4✓ Branch 0 taken 1808486 times.
✓ Branch 1 taken 4855 times.
✓ Branch 2 taken 1808504 times.
✗ Branch 3 not taken.
|
1813356 | DEBUG_SYNC(thd, "after_join_optimize"); |
| 1032 | |||
| 1033 | 1813359 | error = 0; | |
| 1034 | 1813359 | return false; | |
| 1035 | |||
| 1036 | 74593 | setup_subq_exit: | |
| 1037 | |||
| 1038 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 74593 times.
|
74593 | assert(zero_result_cause != nullptr); |
| 1039 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 74593 times.
|
74593 | assert(m_root_access_path != nullptr); |
| 1040 | /* | ||
| 1041 | Even with zero matching rows, subqueries in the HAVING clause may | ||
| 1042 | need to be evaluated if there are aggregate functions in the | ||
| 1043 | query. If this JOIN is part of an outer query, subqueries in HAVING may | ||
| 1044 | be evaluated several times in total; so subquery materialization makes | ||
| 1045 | sense. | ||
| 1046 | */ | ||
| 1047 | 74593 | child_subquery_can_materialize = true; | |
| 1048 | |||
| 1049 |
1/2✓ Branch 0 taken 74593 times.
✗ Branch 1 not taken.
|
74593 | trace_steps.end(); // because all steps are done |
| 1050 |
2/4✓ Branch 0 taken 74593 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 74593 times.
✗ Branch 3 not taken.
|
74593 | Opt_trace_object(trace, "empty_result").add_alnum("cause", zero_result_cause); |
| 1051 | |||
| 1052 | 74593 | having_for_explain = having_cond; | |
| 1053 | 74593 | error = 0; | |
| 1054 | |||
| 1055 |
3/4✓ Branch 0 taken 74593 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52253 times.
✓ Branch 3 taken 22340 times.
|
74593 | if (!qep_tab && best_ref) { |
| 1056 | /* | ||
| 1057 | After creation of JOIN_TABs in make_join_plan(), we have shortcut due to | ||
| 1058 | some zero_result_cause. For simplification, if we have JOIN_TABs we | ||
| 1059 | want QEP_TABs too. | ||
| 1060 | */ | ||
| 1061 |
2/4✓ Branch 0 taken 52253 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 52253 times.
|
52253 | if (alloc_qep(tables)) return true; /* purecov: inspected */ |
| 1062 |
1/2✓ Branch 0 taken 52253 times.
✗ Branch 1 not taken.
|
52253 | unplug_join_tabs(); |
| 1063 | } | ||
| 1064 | |||
| 1065 |
1/2✓ Branch 0 taken 74593 times.
✗ Branch 1 not taken.
|
74593 | set_plan_state(ZERO_RESULT); |
| 1066 | 74593 | return false; | |
| 1067 | 9008663 | } | |
| 1068 | |||
| 1069 | 2111 | void JOIN::change_to_access_path_without_in2exists() { | |
| 1070 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2111 times.
|
2111 | if (m_root_access_path_no_in2exists != nullptr) { |
| 1071 | ✗ | m_root_access_path = m_root_access_path_no_in2exists; | |
| 1072 | } | ||
| 1073 | 2111 | } | |
| 1074 | |||
| 1075 | 68511 | void JOIN::create_access_paths_for_zero_rows() { | |
| 1076 |
2/2✓ Branch 0 taken 7460 times.
✓ Branch 1 taken 61051 times.
|
68511 | if (send_row_on_empty_set()) { |
| 1077 | // Aggregate no rows into an aggregate row. | ||
| 1078 | 7460 | m_root_access_path = | |
| 1079 | 7460 | NewZeroRowsAggregatedAccessPath(thd, zero_result_cause); | |
| 1080 | 7460 | m_root_access_path = | |
| 1081 | 7460 | attach_access_paths_for_having_and_limit(m_root_access_path); | |
| 1082 | } else { | ||
| 1083 | // Send no row at all (so also no need to check HAVING or LIMIT). | ||
| 1084 | 61051 | m_root_access_path = NewZeroRowsAccessPath(thd, zero_result_cause); | |
| 1085 | } | ||
| 1086 | 68511 | m_root_access_path = | |
| 1087 | 68511 | attach_access_path_for_update_or_delete(m_root_access_path); | |
| 1088 | 68511 | } | |
| 1089 | |||
| 1090 | /** | ||
| 1091 | Push (parts of) the query execution down to the storage engines if they | ||
| 1092 | can provide faster execution of the query, or part of it. | ||
| 1093 | |||
| 1094 | The handler will inspect the QEP through the | ||
| 1095 | AQP (Abstract Query Plan) and extract from it whatever | ||
| 1096 | it might implement of pushed execution. | ||
| 1097 | |||
| 1098 | It is the responsibility of the handler to store | ||
| 1099 | any information it need for the later execution of | ||
| 1100 | pushed queries and conditions. | ||
| 1101 | |||
| 1102 | @retval false Success. | ||
| 1103 | @retval true Error, error code saved in member JOIN::error. | ||
| 1104 | */ | ||
| 1105 | 1813462 | bool JOIN::push_to_engines() { | |
| 1106 |
1/2✓ Branch 0 taken 1813550 times.
✗ Branch 1 not taken.
|
1813462 | DBUG_TRACE; |
| 1107 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1813550 times.
|
1813550 | assert(m_root_access_path != nullptr); |
| 1108 | |||
| 1109 |
2/2✓ Branch 0 taken 3862065 times.
✓ Branch 1 taken 1813506 times.
|
5675571 | for (TABLE_LIST *tl = query_block->leaf_tables; tl; tl = tl->next_leaf) { |
| 1110 |
1/2✓ Branch 0 taken 3862021 times.
✗ Branch 1 not taken.
|
3862065 | const handlerton *hton = tl->table->file->hton_supporting_engine_pushdown(); |
| 1111 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3862021 times.
|
3862021 | if (hton != nullptr) { // Involved an engine supporting pushdown. |
| 1112 | ✗ | if (unlikely(hton->push_to_engine(thd, m_root_access_path, this))) { | |
| 1113 | ✗ | return true; | |
| 1114 | } | ||
| 1115 | ✗ | break; // Assume that at most a single handlerton per query support | |
| 1116 | // pushdown | ||
| 1117 | } | ||
| 1118 | } | ||
| 1119 | 1813506 | return false; | |
| 1120 | 1813506 | } | |
| 1121 | |||
| 1122 | /** | ||
| 1123 | Substitute all expressions in the WHERE condition and ORDER/GROUP lists | ||
| 1124 | that match generated columns (GC) expressions with GC fields, if any. | ||
| 1125 | |||
| 1126 | @details This function does 3 things: | ||
| 1127 | 1) Creates list of all GC fields that are a part of a key and the GC | ||
| 1128 | expression is a function. All query tables are scanned. If there's no | ||
| 1129 | such fields, function exits. | ||
| 1130 | 2) By means of Item::compile() WHERE clause is transformed. | ||
| 1131 | @see Item_func::gc_subst_transformer() for details. | ||
| 1132 | 3) If there's ORDER/GROUP BY clauses, this function tries to substitute | ||
| 1133 | expressions in these lists with GC too. It removes from the list of | ||
| 1134 | indexed GC all elements which index blocked by hints. This is done to | ||
| 1135 | reduce amount of further work. Next it goes through ORDER/GROUP BY list | ||
| 1136 | and matches the expression in it against GC expressions in indexed GC | ||
| 1137 | list. When a match is found, the expression is replaced with a new | ||
| 1138 | Item_field for the matched GC field. Also, this new field is added to | ||
| 1139 | the hidden part of all_fields list. | ||
| 1140 | |||
| 1141 | @param thd thread handle | ||
| 1142 | @param query_block the current select | ||
| 1143 | @param where_cond the WHERE condition, possibly NULL | ||
| 1144 | @param group_list the GROUP BY clause, possibly NULL | ||
| 1145 | @param order the ORDER BY clause, possibly NULL | ||
| 1146 | |||
| 1147 | @return true if the GROUP BY clause or the ORDER BY clause was | ||
| 1148 | changed, false otherwise | ||
| 1149 | */ | ||
| 1150 | |||
| 1151 | 1703124 | bool substitute_gc(THD *thd, Query_block *query_block, Item *where_cond, | |
| 1152 | ORDER *group_list, ORDER *order) { | ||
| 1153 | 1703124 | List<Field> indexed_gc; | |
| 1154 | 1703163 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 1155 |
1/2✓ Branch 0 taken 1703245 times.
✗ Branch 1 not taken.
|
1703163 | Opt_trace_object trace_wrapper(trace); |
| 1156 |
1/2✓ Branch 0 taken 1703259 times.
✗ Branch 1 not taken.
|
1703245 | Opt_trace_object subst_gc(trace, "substitute_generated_columns"); |
| 1157 | |||
| 1158 | // Collect all GCs that are a part of a key | ||
| 1159 |
2/2✓ Branch 0 taken 3766966 times.
✓ Branch 1 taken 1703388 times.
|
5470354 | for (TABLE_LIST *tl = query_block->leaf_tables; tl; tl = tl->next_leaf) { |
| 1160 |
2/2✓ Branch 0 taken 441458 times.
✓ Branch 1 taken 3325508 times.
|
3766966 | if (tl->table->s->keys == 0) continue; |
| 1161 |
2/2✓ Branch 0 taken 34699585 times.
✓ Branch 1 taken 3325637 times.
|
38025222 | for (uint i = 0; i < tl->table->s->fields; i++) { |
| 1162 | 34699585 | Field *fld = tl->table->field[i]; | |
| 1163 | 34699585 | if (fld->is_gcol() && | |
| 1164 |
2/2✓ Branch 0 taken 21637 times.
✓ Branch 1 taken 6600 times.
|
28237 | !(fld->part_of_key.is_clear_all() && |
| 1165 |
6/6✓ Branch 0 taken 28237 times.
✓ Branch 1 taken 34671097 times.
✓ Branch 2 taken 3355 times.
✓ Branch 3 taken 18282 times.
✓ Branch 4 taken 8492 times.
✓ Branch 5 taken 34691046 times.
|
34731130 | fld->part_of_prefixkey.is_clear_all()) && |
| 1166 |
3/4✓ Branch 0 taken 10159 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8492 times.
✓ Branch 3 taken 1667 times.
|
9955 | fld->gcol_info->expr_item->can_be_substituted_for_gc()) { |
| 1167 | // Don't check allowed keys here as conditions/group/order use | ||
| 1168 | // different keymaps for that. | ||
| 1169 |
1/2✓ Branch 0 taken 8668 times.
✗ Branch 1 not taken.
|
8492 | indexed_gc.push_back(fld); |
| 1170 | } | ||
| 1171 | } | ||
| 1172 | } | ||
| 1173 | // No GC in the tables used in the query | ||
| 1174 |
2/2✓ Branch 0 taken 1695595 times.
✓ Branch 1 taken 7793 times.
|
1703388 | if (indexed_gc.elements == 0) return false; |
| 1175 | |||
| 1176 |
2/2✓ Branch 0 taken 7513 times.
✓ Branch 1 taken 280 times.
|
7793 | if (where_cond) { |
| 1177 | // Item_func::compile will dereference this pointer, provide valid value. | ||
| 1178 | 7513 | uchar i, *dummy = &i; | |
| 1179 |
1/2✓ Branch 0 taken 7513 times.
✗ Branch 1 not taken.
|
7513 | if (where_cond->compile(&Item::gc_subst_analyzer, &dummy, |
| 1180 | &Item::gc_subst_transformer, | ||
| 1181 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7511 times.
|
7513 | pointer_cast<uchar *>(&indexed_gc)) == nullptr) |
| 1182 | 2 | return true; | |
| 1183 |
1/2✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
|
7511 | subst_gc.add("resulting_condition", where_cond); |
| 1184 | } | ||
| 1185 | |||
| 1186 | // An error occur during substitution. Let caller handle it. | ||
| 1187 |
2/4✓ Branch 0 taken 7687 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7687 times.
|
7791 | if (thd->is_error()) return false; |
| 1188 | |||
| 1189 |
4/4✓ Branch 0 taken 7651 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 7334 times.
✓ Branch 3 taken 317 times.
|
7687 | if (!(group_list || order)) return false; |
| 1190 | // Filter out GCs that do not have index usable for GROUP/ORDER | ||
| 1191 | Field *gc; | ||
| 1192 |
1/2✓ Branch 0 taken 353 times.
✗ Branch 1 not taken.
|
353 | List_iterator<Field> li(indexed_gc); |
| 1193 | |||
| 1194 |
2/2✓ Branch 0 taken 531 times.
✓ Branch 1 taken 353 times.
|
884 | while ((gc = li++)) { |
| 1195 | 531 | Key_map tkm = gc->part_of_key; | |
| 1196 |
2/2✓ Branch 0 taken 109 times.
✓ Branch 1 taken 422 times.
|
953 | tkm.intersect(group_list ? gc->table->keys_in_use_for_group_by |
| 1197 | 422 | : gc->table->keys_in_use_for_order_by); | |
| 1198 |
3/4✓ Branch 0 taken 130 times.
✓ Branch 1 taken 401 times.
✓ Branch 2 taken 130 times.
✗ Branch 3 not taken.
|
531 | if (tkm.is_clear_all()) li.remove(); |
| 1199 | } | ||
| 1200 |
2/2✓ Branch 0 taken 119 times.
✓ Branch 1 taken 234 times.
|
353 | if (!indexed_gc.elements) return false; |
| 1201 | |||
| 1202 | // Index could be used for ORDER only if there is no GROUP | ||
| 1203 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 198 times.
|
234 | ORDER *list = group_list ? group_list : order; |
| 1204 | 234 | bool changed = false; | |
| 1205 |
2/2✓ Branch 0 taken 406 times.
✓ Branch 1 taken 234 times.
|
640 | for (ORDER *ord = list; ord; ord = ord->next) { |
| 1206 | 406 | li.rewind(); | |
| 1207 |
3/4✓ Branch 0 taken 406 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 393 times.
✓ Branch 3 taken 13 times.
|
406 | if (!(*ord->item)->can_be_substituted_for_gc()) continue; |
| 1208 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 12 times.
|
25 | while ((gc = li++)) { |
| 1209 | Item_field *const field = | ||
| 1210 |
2/4✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | get_gc_for_expr(*ord->item, gc, gc->result_type()); |
| 1211 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12 times.
|
13 | if (field != nullptr) { |
| 1212 | 1 | changed = true; | |
| 1213 | /* Add new field to field list. */ | ||
| 1214 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | Item **new_field = query_block->add_hidden_item(field); |
| 1215 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | thd->change_item_tree(ord->item, *new_field); |
| 1216 | 1 | query_block->hidden_items_from_optimization++; | |
| 1217 | 1 | break; | |
| 1218 | } | ||
| 1219 | } | ||
| 1220 | } | ||
| 1221 | // An error occur during substitution. Let caller handle it. | ||
| 1222 |
2/4✓ Branch 0 taken 234 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 234 times.
|
234 | if (thd->is_error()) return false; |
| 1223 | |||
| 1224 |
4/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 233 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 234 times.
|
234 | if (changed && trace->is_started()) { |
| 1225 | ✗ | String str; | |
| 1226 | ✗ | Query_block::print_order( | |
| 1227 | thd, &str, list, | ||
| 1228 | enum_query_type(QT_TO_SYSTEM_CHARSET | QT_SHOW_SELECT_NUMBER | | ||
| 1229 | QT_NO_DEFAULT_DB)); | ||
| 1230 | ✗ | subst_gc.add_utf8(group_list ? "resulting_GROUP_BY" : "resulting_ORDER_BY", | |
| 1231 | ✗ | str.ptr(), str.length()); | |
| 1232 | } | ||
| 1233 | 234 | return changed; | |
| 1234 | 1703284 | } | |
| 1235 | |||
| 1236 | /** | ||
| 1237 | Sets the plan's state of the JOIN. This is always the final step of | ||
| 1238 | optimization; starting from this call, we expose the plan to other | ||
| 1239 | connections (via EXPLAIN CONNECTION) so the plan has to be final. | ||
| 1240 | keyread_optim is set here. | ||
| 1241 | */ | ||
| 1242 | 18016937 | void JOIN::set_plan_state(enum_plan_state plan_state_arg) { | |
| 1243 | // A plan should not change to another plan: | ||
| 1244 |
3/4✓ Branch 0 taken 9008361 times.
✓ Branch 1 taken 9008576 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9008361 times.
|
18016937 | assert(plan_state_arg == NO_PLAN || plan_state == NO_PLAN); |
| 1245 |
4/4✓ Branch 0 taken 9008709 times.
✓ Branch 1 taken 9008228 times.
✓ Branch 2 taken 9008346 times.
✓ Branch 3 taken 363 times.
|
18016937 | if (plan_state == NO_PLAN && plan_state_arg != NO_PLAN) { |
| 1246 |
2/2✓ Branch 0 taken 1866801 times.
✓ Branch 1 taken 7141545 times.
|
9008346 | if (qep_tab != nullptr) { |
| 1247 | /* | ||
| 1248 | We want to cover primary tables, tmp tables. Note that | ||
| 1249 | make_tmp_tables_info() may have added a sort to the first non-const | ||
| 1250 | primary table, so it's important to do this assignment after | ||
| 1251 | make_tmp_tables_info(). | ||
| 1252 | */ | ||
| 1253 |
2/2✓ Branch 0 taken 6264750 times.
✓ Branch 1 taken 1866819 times.
|
8131569 | for (uint i = const_tables; i < tables; ++i) { |
| 1254 | 6264750 | qep_tab[i].set_condition_optim(); | |
| 1255 | 6264757 | qep_tab[i].set_keyread_optim(); | |
| 1256 | } | ||
| 1257 | } | ||
| 1258 | } | ||
| 1259 | |||
| 1260 |
2/2✓ Branch 0 taken 17981642 times.
✓ Branch 1 taken 35307 times.
|
18016955 | DEBUG_SYNC(thd, "before_set_plan"); |
| 1261 | |||
| 1262 | // If SQLCOM_END, no thread is explaining our statement anymore. | ||
| 1263 | 18017018 | const bool need_lock = thd->query_plan.get_command() != SQLCOM_END; | |
| 1264 | |||
| 1265 |
2/2✓ Branch 0 taken 9099896 times.
✓ Branch 1 taken 8917085 times.
|
18016981 | if (need_lock) thd->lock_query_plan(); |
| 1266 | 18016947 | plan_state = plan_state_arg; | |
| 1267 |
2/2✓ Branch 0 taken 9099869 times.
✓ Branch 1 taken 8917078 times.
|
18016947 | if (need_lock) thd->unlock_query_plan(); |
| 1268 | 18016993 | } | |
| 1269 | |||
| 1270 | 1866701 | bool JOIN::alloc_qep(uint n) { | |
| 1271 | static_assert(MAX_TABLES <= INT_MAX8, "plan_idx needs to be wide enough."); | ||
| 1272 | |||
| 1273 |
3/6✓ Branch 0 taken 1866708 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1866719 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1866762 times.
✗ Branch 5 not taken.
|
1866701 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 1274 | |||
| 1275 | 1866767 | qep_tab = new (thd->mem_root) | |
| 1276 |
4/6✓ Branch 0 taken 1866767 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1866773 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8271278 times.
✓ Branch 5 taken 1866701 times.
|
12004728 | QEP_TAB[n + 1]; // The last one holds only the final op_type. |
| 1277 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1866700 times.
|
1866700 | if (!qep_tab) return true; /* purecov: inspected */ |
| 1278 |
2/2✓ Branch 0 taken 6405145 times.
✓ Branch 1 taken 1866696 times.
|
8271841 | for (uint i = 0; i < n; ++i) qep_tab[i].init(best_ref[i]); |
| 1279 | 1866696 | return false; | |
| 1280 | } | ||
| 1281 | |||
| 1282 | 6405120 | void QEP_TAB::init(JOIN_TAB *jt) { | |
| 1283 | 6405120 | jt->share_qs(this); | |
| 1284 | 6405181 | set_table(table()); // to update table()->reginfo.qep_tab | |
| 1285 | 6405117 | table_ref = jt->table_ref; | |
| 1286 | 6405117 | } | |
| 1287 | |||
| 1288 | /// @returns semijoin strategy for this table. | ||
| 1289 | 155937 | uint QEP_TAB::get_sj_strategy() const { | |
| 1290 |
2/2✓ Branch 0 taken 126812 times.
✓ Branch 1 taken 29125 times.
|
155937 | if (first_sj_inner() == NO_PLAN_IDX) return SJ_OPT_NONE; |
| 1291 | 29125 | const uint s = join()->qep_tab[first_sj_inner()].position()->sj_strategy; | |
| 1292 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29125 times.
|
29125 | assert(s != SJ_OPT_NONE); |
| 1293 | 29125 | return s; | |
| 1294 | } | ||
| 1295 | |||
| 1296 | /** | ||
| 1297 | Return the index used for a table in a QEP | ||
| 1298 | |||
| 1299 | The various access methods have different places where the index/key | ||
| 1300 | number is stored, so this function is needed to return the correct value. | ||
| 1301 | |||
| 1302 | @returns index number, or MAX_KEY if not applicable. | ||
| 1303 | |||
| 1304 | JT_SYSTEM and JT_ALL does not use an index, and will always return MAX_KEY. | ||
| 1305 | |||
| 1306 | JT_INDEX_MERGE supports more than one index. Hence MAX_KEY is returned and | ||
| 1307 | a further inspection is needed. | ||
| 1308 | */ | ||
| 1309 | 5028 | uint QEP_TAB::effective_index() const { | |
| 1310 |
5/6✗ Branch 0 not taken.
✓ Branch 1 taken 627 times.
✓ Branch 2 taken 917 times.
✓ Branch 3 taken 23 times.
✓ Branch 4 taken 337 times.
✓ Branch 5 taken 3124 times.
|
5028 | switch (type()) { |
| 1311 | ✗ | case JT_SYSTEM: | |
| 1312 | ✗ | assert(ref().key == -1); | |
| 1313 | ✗ | return MAX_KEY; | |
| 1314 | |||
| 1315 | 627 | case JT_CONST: | |
| 1316 | case JT_EQ_REF: | ||
| 1317 | case JT_REF_OR_NULL: | ||
| 1318 | case JT_REF: | ||
| 1319 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 627 times.
|
627 | assert(ref().key != -1); |
| 1320 | 627 | return uint(ref().key); | |
| 1321 | |||
| 1322 | 917 | case JT_INDEX_SCAN: | |
| 1323 | case JT_FT: | ||
| 1324 | 917 | return index(); | |
| 1325 | |||
| 1326 | 23 | case JT_INDEX_MERGE: | |
| 1327 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | assert(used_index(range_scan()) == MAX_KEY); |
| 1328 | 23 | return MAX_KEY; | |
| 1329 | |||
| 1330 | 337 | case JT_RANGE: | |
| 1331 | 337 | return used_index(range_scan()); | |
| 1332 | |||
| 1333 | 3124 | case JT_ALL: | |
| 1334 | default: | ||
| 1335 | // @todo Check why JT_UNKNOWN is a valid value here. | ||
| 1336 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 3124 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
3124 | assert(type() == JT_ALL || type() == JT_UNKNOWN); |
| 1337 | 3124 | return MAX_KEY; | |
| 1338 | } | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | 17312008 | uint JOIN_TAB::get_sj_strategy() const { | |
| 1342 |
2/2✓ Branch 0 taken 17105880 times.
✓ Branch 1 taken 206299 times.
|
17312008 | if (first_sj_inner() == NO_PLAN_IDX) return SJ_OPT_NONE; |
| 1343 |
3/6✓ Branch 0 taken 206356 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 206356 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 206356 times.
✗ Branch 5 not taken.
|
206299 | ASSERT_BEST_REF_IN_JOIN_ORDER(join()); |
| 1344 | 206356 | JOIN_TAB *tab = join()->best_ref[first_sj_inner()]; | |
| 1345 | 206356 | uint s = tab->position()->sj_strategy; | |
| 1346 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 206356 times.
|
206356 | assert(s != SJ_OPT_NONE); |
| 1347 | 206356 | return s; | |
| 1348 | } | ||
| 1349 | |||
| 1350 | 1814531 | int JOIN::replace_index_subquery() { | |
| 1351 |
1/2✓ Branch 0 taken 1814570 times.
✗ Branch 1 not taken.
|
1814531 | DBUG_TRACE; |
| 1352 |
3/6✓ Branch 0 taken 1814570 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1814570 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1814570 times.
✗ Branch 5 not taken.
|
1814570 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 1353 | |||
| 1354 | 1814570 | if (!group_list.empty() || | |
| 1355 |
2/2✓ Branch 0 taken 95557 times.
✓ Branch 1 taken 1702874 times.
|
1798430 | !(query_expression()->item && |
| 1356 |
3/4✓ Branch 0 taken 95557 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10897 times.
✓ Branch 3 taken 84660 times.
|
95557 | query_expression()->item->substype() == Item_subselect::IN_SUBS) || |
| 1357 |
10/10✓ Branch 0 taken 1798430 times.
✓ Branch 1 taken 16141 times.
✓ Branch 2 taken 7555 times.
✓ Branch 3 taken 3342 times.
✓ Branch 4 taken 5963 times.
✓ Branch 5 taken 1592 times.
✓ Branch 6 taken 112 times.
✓ Branch 7 taken 5815 times.
✓ Branch 8 taken 1808745 times.
✓ Branch 9 taken 5791 times.
|
3613002 | primary_tables != 1 || !where_cond || query_expression()->is_union()) |
| 1358 | 1808745 | return 0; | |
| 1359 | |||
| 1360 | // Guaranteed by remove_redundant_subquery_clauses(): | ||
| 1361 |
2/4✓ Branch 0 taken 5815 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5815 times.
✗ Branch 3 not taken.
|
5791 | assert(order.empty() && !select_distinct); |
| 1362 | |||
| 1363 | Item_in_subselect *const in_subs = | ||
| 1364 | 5815 | static_cast<Item_in_subselect *>(query_expression()->item); | |
| 1365 | 5815 | bool found_engine = false; | |
| 1366 | |||
| 1367 | 5815 | JOIN_TAB *const first_join_tab = best_ref[0]; | |
| 1368 | |||
| 1369 |
2/2✓ Branch 0 taken 5451 times.
✓ Branch 1 taken 364 times.
|
5815 | if (in_subs->strategy == Subquery_strategy::SUBQ_MATERIALIZATION) { |
| 1370 | // We cannot have two engines at the same time | ||
| 1371 |
4/6✓ Branch 0 taken 64 times.
✓ Branch 1 taken 5387 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 5451 times.
✗ Branch 5 not taken.
|
5515 | } else if (first_join_tab->table_ref->is_view_or_derived() && |
| 1372 | 64 | first_join_tab->table_ref->derived_query_expression() | |
| 1373 | 64 | ->is_recursive()) { | |
| 1374 | // The index subquery engine, which runs the derived table machinery | ||
| 1375 | // from the old executor, is not capable of materializing a WITH RECURSIVE | ||
| 1376 | // query from the iterator executor. Thus, be conservative here, so that the | ||
| 1377 | // case never happens. | ||
| 1378 |
2/2✓ Branch 0 taken 3661 times.
✓ Branch 1 taken 1790 times.
|
5451 | } else if (having_cond == nullptr) { |
| 1379 | 3661 | const join_type type = first_join_tab->type(); | |
| 1380 |
6/6✓ Branch 0 taken 3305 times.
✓ Branch 1 taken 356 times.
✓ Branch 2 taken 622 times.
✓ Branch 3 taken 2683 times.
✓ Branch 4 taken 953 times.
✓ Branch 5 taken 2708 times.
|
4639 | if ((type == JT_EQ_REF || type == JT_REF) && |
| 1381 |
2/2✓ Branch 0 taken 953 times.
✓ Branch 1 taken 25 times.
|
978 | first_join_tab->ref().items[0]->item_name.ptr() == in_left_expr_name) { |
| 1382 | 953 | found_engine = true; | |
| 1383 | } | ||
| 1384 | 1790 | } else if (first_join_tab->type() == JT_REF_OR_NULL && | |
| 1385 |
2/2✓ Branch 0 taken 263 times.
✓ Branch 1 taken 27 times.
|
290 | first_join_tab->ref().items[0]->item_name.ptr() == |
| 1386 |
4/4✓ Branch 0 taken 290 times.
✓ Branch 1 taken 1500 times.
✓ Branch 2 taken 263 times.
✓ Branch 3 taken 1527 times.
|
2080 | in_left_expr_name && |
| 1387 |
2/4✓ Branch 0 taken 263 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 263 times.
✗ Branch 3 not taken.
|
263 | having_cond->created_by_in2exists()) { |
| 1388 | 263 | found_engine = true; | |
| 1389 | } | ||
| 1390 | |||
| 1391 |
2/2✓ Branch 0 taken 4599 times.
✓ Branch 1 taken 1216 times.
|
5815 | if (!found_engine) return 0; |
| 1392 | |||
| 1393 | /* Remove redundant predicates and cache constant expressions */ | ||
| 1394 |
2/4✓ Branch 0 taken 1216 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1216 times.
|
1216 | if (finalize_table_conditions()) return -1; |
| 1395 | |||
| 1396 |
2/4✓ Branch 0 taken 1216 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1216 times.
|
1216 | if (alloc_qep(tables)) return -1; /* purecov: inspected */ |
| 1397 |
1/2✓ Branch 0 taken 1216 times.
✗ Branch 1 not taken.
|
1216 | unplug_join_tabs(); |
| 1398 | |||
| 1399 | 1216 | error = 0; | |
| 1400 | 1216 | QEP_TAB *const first_qep_tab = &qep_tab[0]; | |
| 1401 | |||
| 1402 |
2/2✓ Branch 0 taken 811 times.
✓ Branch 1 taken 405 times.
|
1216 | if (first_qep_tab->table()->covering_keys.is_set(first_qep_tab->ref().key)) { |
| 1403 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 811 times.
|
811 | assert(!first_qep_tab->table()->no_keyread); |
| 1404 |
1/2✓ Branch 0 taken 811 times.
✗ Branch 1 not taken.
|
811 | first_qep_tab->table()->set_keyread(true); |
| 1405 | } | ||
| 1406 | |||
| 1407 | subselect_indexsubquery_engine *engine = | ||
| 1408 | 1216 | new (thd->mem_root) subselect_indexsubquery_engine( | |
| 1409 | 1216 | first_qep_tab->table(), first_qep_tab->table_ref, | |
| 1410 | 1216 | first_qep_tab->ref(), first_qep_tab->type(), | |
| 1411 | 1216 | down_cast<Item_in_subselect *>(query_expression()->item), | |
| 1412 |
1/2✓ Branch 0 taken 1216 times.
✗ Branch 1 not taken.
|
1216 | first_qep_tab->condition(), having_cond); |
| 1413 | 1216 | query_expression()->item->set_indexsubquery_engine(engine); | |
| 1414 | 1216 | return 1; | |
| 1415 | 1814560 | } | |
| 1416 | |||
| 1417 | 1814517 | bool JOIN::optimize_distinct_group_order() { | |
| 1418 |
1/2✓ Branch 0 taken 1814624 times.
✗ Branch 1 not taken.
|
1814517 | DBUG_TRACE; |
| 1419 |
4/6✓ Branch 0 taken 1814624 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1814590 times.
✓ Branch 3 taken 34 times.
✓ Branch 4 taken 1814595 times.
✗ Branch 5 not taken.
|
1814624 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 1420 | 1814595 | const bool windowing = m_windows.elements > 0; | |
| 1421 |
2/2✓ Branch 0 taken 1795870 times.
✓ Branch 1 taken 14567 times.
|
1810437 | const bool may_trace = select_distinct || !group_list.empty() || |
| 1422 |
6/6✓ Branch 0 taken 1810437 times.
✓ Branch 1 taken 4158 times.
✓ Branch 2 taken 1251823 times.
✓ Branch 3 taken 544048 times.
✓ Branch 4 taken 1250346 times.
✓ Branch 5 taken 1477 times.
|
4875378 | !order.empty() || windowing || |
| 1423 |
2/2✓ Branch 0 taken 337051 times.
✓ Branch 1 taken 913295 times.
|
1250346 | tmp_table_param.sum_func_count; |
| 1424 | 1814596 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 1425 |
1/2✓ Branch 0 taken 1814596 times.
✗ Branch 1 not taken.
|
1814596 | Opt_trace_disable_I_S trace_disabled(trace, !may_trace); |
| 1426 |
1/2✓ Branch 0 taken 1814611 times.
✗ Branch 1 not taken.
|
1814596 | Opt_trace_object wrapper(trace); |
| 1427 |
1/2✓ Branch 0 taken 1814617 times.
✗ Branch 1 not taken.
|
1814611 | Opt_trace_object trace_opt(trace, "optimizing_distinct_group_by_order_by"); |
| 1428 | /* Optimize distinct away if possible */ | ||
| 1429 | { | ||
| 1430 | 1814617 | ORDER *org_order = order.order; | |
| 1431 | 1814574 | order = ORDER_with_src( | |
| 1432 |
1/2✓ Branch 0 taken 1814574 times.
✗ Branch 1 not taken.
|
1814617 | remove_const(order.order, where_cond, rollup_state == RollupState::NONE, |
| 1433 | &simple_order, false), | ||
| 1434 | order.src); | ||
| 1435 |
3/4✓ Branch 0 taken 1814605 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 1814568 times.
|
1814592 | if (thd->is_error()) { |
| 1436 | 37 | error = 1; | |
| 1437 |
3/8✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
37 | DBUG_PRINT("error", ("Error from remove_const")); |
| 1438 | 37 | return true; | |
| 1439 | } | ||
| 1440 | |||
| 1441 | /* | ||
| 1442 | If we are using ORDER BY NULL or ORDER BY const_expression, | ||
| 1443 | return result in any order (even if we are using a GROUP BY) | ||
| 1444 | */ | ||
| 1445 |
6/6✓ Branch 0 taken 1269730 times.
✓ Branch 1 taken 544754 times.
✓ Branch 2 taken 3634 times.
✓ Branch 3 taken 1266096 times.
✓ Branch 4 taken 3634 times.
✓ Branch 5 taken 1810850 times.
|
1814568 | if (order.empty() && org_order) skip_sort_order = true; |
| 1446 | } | ||
| 1447 | /* | ||
| 1448 | Check if we can optimize away GROUP BY/DISTINCT. | ||
| 1449 | We can do that if there are no aggregate functions, the | ||
| 1450 | fields in DISTINCT clause (if present) and/or columns in GROUP BY | ||
| 1451 | (if present) contain direct references to all key parts of | ||
| 1452 | an unique index (in whatever order) and if the key parts of the | ||
| 1453 | unique index cannot contain NULLs. | ||
| 1454 | Note that the unique keys for DISTINCT and GROUP BY should not | ||
| 1455 | be the same (as long as they are unique). | ||
| 1456 | |||
| 1457 | The FROM clause must contain a single non-constant table. | ||
| 1458 | |||
| 1459 | @todo Apart from the LIS test, every condition depends only on facts | ||
| 1460 | which can be known in Query_block::prepare(), possibly this block should | ||
| 1461 | move there. | ||
| 1462 | */ | ||
| 1463 | |||
| 1464 | 1814484 | JOIN_TAB *const tab = best_ref[const_tables]; | |
| 1465 | |||
| 1466 |
4/4✓ Branch 0 taken 1273932 times.
✓ Branch 1 taken 12874 times.
✓ Branch 2 taken 3120 times.
✓ Branch 3 taken 1270812 times.
|
3101290 | if (plan_is_single_table() && (!group_list.empty() || select_distinct) && |
| 1467 |
8/8✓ Branch 0 taken 1286806 times.
✓ Branch 1 taken 527685 times.
✓ Branch 2 taken 5747 times.
✓ Branch 3 taken 10247 times.
✓ Branch 4 taken 319 times.
✓ Branch 5 taken 5428 times.
✓ Branch 6 taken 5572 times.
✓ Branch 7 taken 1808910 times.
|
3107354 | !tmp_table_param.sum_func_count && |
| 1468 | 5747 | (!tab->range_scan() || | |
| 1469 |
2/2✓ Branch 0 taken 144 times.
✓ Branch 1 taken 166 times.
|
319 | tab->range_scan()->type != AccessPath::GROUP_INDEX_SKIP_SCAN)) { |
| 1470 |
6/6✓ Branch 0 taken 2529 times.
✓ Branch 1 taken 3043 times.
✓ Branch 2 taken 2427 times.
✓ Branch 3 taken 102 times.
✓ Branch 4 taken 273 times.
✓ Branch 5 taken 5299 times.
|
7999 | if (!group_list.empty() && rollup_state == RollupState::NONE && |
| 1471 |
2/2✓ Branch 0 taken 273 times.
✓ Branch 1 taken 2154 times.
|
2427 | list_contains_unique_index(tab, find_field_in_order_list, |
| 1472 |
1/2✓ Branch 0 taken 2427 times.
✗ Branch 1 not taken.
|
2427 | (void *)group_list.order)) { |
| 1473 | /* | ||
| 1474 | We have found that grouping can be removed since groups correspond to | ||
| 1475 | only one row anyway. | ||
| 1476 | */ | ||
| 1477 | 273 | group_list.clean(); | |
| 1478 | 273 | grouped = false; | |
| 1479 | } | ||
| 1480 |
4/4✓ Branch 0 taken 3106 times.
✓ Branch 1 taken 2466 times.
✓ Branch 2 taken 191 times.
✓ Branch 3 taken 5381 times.
|
8678 | if (select_distinct && |
| 1481 |
3/4✓ Branch 0 taken 3106 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 191 times.
✓ Branch 3 taken 2915 times.
|
3106 | list_contains_unique_index(tab, find_field_in_item_list, fields)) { |
| 1482 | 191 | select_distinct = false; | |
| 1483 |
1/2✓ Branch 0 taken 191 times.
✗ Branch 1 not taken.
|
191 | trace_opt.add("distinct_is_on_unique", true) |
| 1484 |
1/2✓ Branch 0 taken 191 times.
✗ Branch 1 not taken.
|
191 | .add("removed_distinct", true); |
| 1485 | } | ||
| 1486 | } | ||
| 1487 |
4/4✓ Branch 0 taken 1462947 times.
✓ Branch 1 taken 337057 times.
✓ Branch 2 taken 1461362 times.
✓ Branch 3 taken 1585 times.
|
3614486 | if (!(!group_list.empty() || tmp_table_param.sum_func_count || windowing) && |
| 1488 |
8/8✓ Branch 0 taken 1800004 times.
✓ Branch 1 taken 14486 times.
✓ Branch 2 taken 3794 times.
✓ Branch 3 taken 1457568 times.
✓ Branch 4 taken 2947 times.
✓ Branch 5 taken 847 times.
✓ Branch 6 taken 2947 times.
✓ Branch 7 taken 1811543 times.
|
3617441 | select_distinct && plan_is_single_table() && |
| 1489 |
1/2✓ Branch 0 taken 2947 times.
✗ Branch 1 not taken.
|
2947 | rollup_state == RollupState::NONE) { |
| 1490 | 2947 | int order_idx = -1, group_idx = -1; | |
| 1491 | /* | ||
| 1492 | We are only using one table. In this case we change DISTINCT to a | ||
| 1493 | GROUP BY query if: | ||
| 1494 | - The GROUP BY can be done through indexes (no sort) and the ORDER | ||
| 1495 | BY only uses selected fields. | ||
| 1496 | (In this case we can later optimize away GROUP BY and ORDER BY) | ||
| 1497 | - We are scanning the whole table without LIMIT | ||
| 1498 | This can happen if: | ||
| 1499 | - We are using CALC_FOUND_ROWS | ||
| 1500 | - We are using an ORDER BY that can't be optimized away. | ||
| 1501 | - Selected expressions are not set functions (those cannot be put | ||
| 1502 | into GROUP BY). | ||
| 1503 | |||
| 1504 | We don't want to use this optimization when we are using LIMIT | ||
| 1505 | because in this case we can just create a temporary table that | ||
| 1506 | holds LIMIT rows and stop when this table is full. | ||
| 1507 | */ | ||
| 1508 |
2/2✓ Branch 0 taken 243 times.
✓ Branch 1 taken 2704 times.
|
2947 | if (!order.empty()) { |
| 1509 | 486 | skip_sort_order = test_if_skip_sort_order( | |
| 1510 | 243 | tab, order, m_select_limit, | |
| 1511 | true, // no_changes | ||
| 1512 |
1/2✓ Branch 0 taken 243 times.
✗ Branch 1 not taken.
|
243 | &tab->table()->keys_in_use_for_order_by, &order_idx); |
| 1513 |
1/2✓ Branch 0 taken 243 times.
✗ Branch 1 not taken.
|
243 | count_field_types(query_block, &tmp_table_param, *fields, false, false); |
| 1514 | } | ||
| 1515 | ORDER *o; | ||
| 1516 | bool all_order_fields_used; | ||
| 1517 | /* | ||
| 1518 | There is possibility where the REF_SLICE_ACTIVE points to | ||
| 1519 | freed-up Items like in case of non-first row of a UPDATE | ||
| 1520 | trigger. Re-load the Items before using the slice. | ||
| 1521 | */ | ||
| 1522 |
1/2✓ Branch 0 taken 2947 times.
✗ Branch 1 not taken.
|
2947 | refresh_base_slice(); |
| 1523 |
2/2✓ Branch 0 taken 2918 times.
✓ Branch 1 taken 29 times.
|
2947 | if ((o = create_order_from_distinct( |
| 1524 |
1/2✓ Branch 0 taken 2947 times.
✗ Branch 1 not taken.
|
2947 | thd, ref_items[REF_SLICE_ACTIVE], order.order, fields, |
| 1525 | /*skip_aggregates=*/true, | ||
| 1526 | /*convert_bit_fields_to_long=*/true, &all_order_fields_used))) { | ||
| 1527 | 2918 | group_list = ORDER_with_src(o, ESC_DISTINCT); | |
| 1528 | const bool skip_group = | ||
| 1529 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 2881 times.
|
2955 | skip_sort_order && |
| 1530 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 10 times.
|
37 | test_if_skip_sort_order(tab, group_list, m_select_limit, |
| 1531 | true, // no_changes | ||
| 1532 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | &tab->table()->keys_in_use_for_group_by, |
| 1533 | 2918 | &group_idx); | |
| 1534 |
1/2✓ Branch 0 taken 2918 times.
✗ Branch 1 not taken.
|
2918 | count_field_types(query_block, &tmp_table_param, *fields, false, false); |
| 1535 | // ORDER BY and GROUP BY are using different indexes, can't skip sorting | ||
| 1536 |
6/6✓ Branch 0 taken 27 times.
✓ Branch 1 taken 2891 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 19 times.
|
2918 | if (group_idx >= 0 && order_idx >= 0 && group_idx != order_idx) |
| 1537 | 2 | skip_sort_order = false; | |
| 1538 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 25 times.
|
27 | if ((skip_group && all_order_fields_used) || |
| 1539 |
6/6✓ Branch 0 taken 27 times.
✓ Branch 1 taken 2891 times.
✓ Branch 2 taken 94 times.
✓ Branch 3 taken 2799 times.
✓ Branch 4 taken 2853 times.
✓ Branch 5 taken 65 times.
|
3039 | m_select_limit == HA_POS_ERROR || |
| 1540 |
4/4✓ Branch 0 taken 33 times.
✓ Branch 1 taken 61 times.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 4 times.
|
94 | (!order.empty() && !skip_sort_order)) { |
| 1541 | /* Change DISTINCT to GROUP BY */ | ||
| 1542 | 2853 | select_distinct = false; | |
| 1543 | /* | ||
| 1544 | group_list was created with ORDER BY clause as prefix and | ||
| 1545 | replaces it. So it must respect ordering. If there is no | ||
| 1546 | ORDER BY, GROUP BY need not have to provide order. | ||
| 1547 | */ | ||
| 1548 |
2/2✓ Branch 0 taken 2616 times.
✓ Branch 1 taken 237 times.
|
2853 | if (order.empty()) { |
| 1549 |
2/2✓ Branch 0 taken 3731 times.
✓ Branch 1 taken 2616 times.
|
6347 | for (ORDER *group = group_list.order; group; group = group->next) |
| 1550 | 3731 | group->direction = ORDER_NOT_RELEVANT; | |
| 1551 | } | ||
| 1552 |
8/8✓ Branch 0 taken 2810 times.
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 2779 times.
✓ Branch 4 taken 19 times.
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 19 times.
✓ Branch 7 taken 2834 times.
|
2853 | if (all_order_fields_used && skip_sort_order && !order.empty()) { |
| 1553 | /* | ||
| 1554 | Force MySQL to read the table in sorted order to get result in | ||
| 1555 | ORDER BY order. | ||
| 1556 | */ | ||
| 1557 | 19 | tmp_table_param.allow_group_via_temp_table = false; | |
| 1558 | } | ||
| 1559 | 2853 | grouped = true; // For end_write_group | |
| 1560 |
1/2✓ Branch 0 taken 2853 times.
✗ Branch 1 not taken.
|
2853 | trace_opt.add("changed_distinct_to_group_by", true); |
| 1561 | } else | ||
| 1562 | 65 | group_list.clean(); | |
| 1563 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | } else if (thd->is_fatal_error()) // End of memory |
| 1564 | ✗ | return true; | |
| 1565 | } | ||
| 1566 | 1814490 | simple_group = false; | |
| 1567 | |||
| 1568 | 1814490 | ORDER *old_group_list = group_list.order; | |
| 1569 | 1814563 | group_list = ORDER_with_src( | |
| 1570 | remove_const(group_list.order, where_cond, | ||
| 1571 |
1/2✓ Branch 0 taken 1814563 times.
✗ Branch 1 not taken.
|
1814490 | rollup_state == RollupState::NONE, &simple_group, true), |
| 1572 | group_list.src); | ||
| 1573 | |||
| 1574 |
3/4✓ Branch 0 taken 1814565 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 1814556 times.
|
1814585 | if (thd->is_error()) { |
| 1575 | 9 | error = 1; | |
| 1576 |
3/8✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
9 | DBUG_PRINT("error", ("Error from remove_const")); |
| 1577 | 9 | return true; | |
| 1578 | } | ||
| 1579 |
6/6✓ Branch 0 taken 17342 times.
✓ Branch 1 taken 1797214 times.
✓ Branch 2 taken 1202 times.
✓ Branch 3 taken 16140 times.
✓ Branch 4 taken 1202 times.
✓ Branch 5 taken 1813354 times.
|
1814556 | if (old_group_list && group_list.empty()) select_distinct = false; |
| 1580 | |||
| 1581 |
6/6✓ Branch 0 taken 1798418 times.
✓ Branch 1 taken 16137 times.
✓ Branch 2 taken 1202 times.
✓ Branch 3 taken 1797216 times.
✓ Branch 4 taken 1202 times.
✓ Branch 5 taken 1813353 times.
|
1814556 | if (group_list.empty() && grouped) { |
| 1582 | 1202 | order.clean(); // The output has only one row | |
| 1583 | 1202 | simple_order = true; | |
| 1584 | 1202 | select_distinct = false; // No need in distinct for 1 row | |
| 1585 | 1202 | group_optimized_away = true; | |
| 1586 | } | ||
| 1587 | |||
| 1588 |
1/2✓ Branch 0 taken 1814497 times.
✗ Branch 1 not taken.
|
1814555 | calc_group_buffer(this, group_list.order); |
| 1589 | 1814497 | send_group_parts = tmp_table_param.group_parts; /* Save org parts */ | |
| 1590 | |||
| 1591 | /* | ||
| 1592 | If ORDER BY is a prefix of GROUP BY and if windowing or ROLLUP | ||
| 1593 | doesn't change this order, ORDER BY can be removed and we can | ||
| 1594 | enforce GROUP BY to provide order. | ||
| 1595 | Also true if the result is one row. | ||
| 1596 | */ | ||
| 1597 |
3/4✓ Branch 0 taken 1814493 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1271334 times.
✓ Branch 3 taken 1209 times.
|
3087040 | if ((test_if_subpart(group_list.order, order.order) && !m_windows_sort && |
| 1598 |
8/8✓ Branch 0 taken 1272543 times.
✓ Branch 1 taken 541950 times.
✓ Branch 2 taken 309 times.
✓ Branch 3 taken 1271025 times.
✓ Branch 4 taken 542450 times.
✓ Branch 5 taken 1065 times.
✓ Branch 6 taken 1271038 times.
✓ Branch 7 taken 543502 times.
|
4171792 | query_block->olap != ROLLUP_TYPE) || |
| 1599 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 542448 times.
|
1085918 | (group_list.empty() && tmp_table_param.sum_func_count)) { |
| 1600 |
2/2✓ Branch 0 taken 2720 times.
✓ Branch 1 taken 1268328 times.
|
1271038 | if (!order.empty()) { |
| 1601 | 2720 | order.clean(); | |
| 1602 |
1/2✓ Branch 0 taken 2720 times.
✗ Branch 1 not taken.
|
2720 | trace_opt.add("removed_order_by", true); |
| 1603 | } | ||
| 1604 |
3/4✓ Branch 0 taken 1270972 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 666 times.
✓ Branch 3 taken 1270306 times.
|
1271048 | if (is_indexed_agg_distinct(this, nullptr)) streaming_aggregation = false; |
| 1605 | } | ||
| 1606 | |||
| 1607 | 1814474 | return false; | |
| 1608 | 1814520 | } | |
| 1609 | |||
| 1610 | 1730913 | void JOIN::test_skip_sort() { | |
| 1611 |
1/2✓ Branch 0 taken 1730983 times.
✗ Branch 1 not taken.
|
1730913 | DBUG_TRACE; |
| 1612 |
3/6✓ Branch 0 taken 1730983 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1730983 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1730984 times.
✗ Branch 5 not taken.
|
1730983 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 1613 | 1730984 | JOIN_TAB *const tab = best_ref[const_tables]; | |
| 1614 | |||
| 1615 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1730984 times.
|
1730984 | assert(m_ordered_index_usage == ORDERED_INDEX_VOID); |
| 1616 | |||
| 1617 |
2/2✓ Branch 0 taken 16136 times.
✓ Branch 1 taken 1714843 times.
|
1730984 | if (!group_list.empty()) // GROUP BY honoured first |
| 1618 | // (DISTINCT was rewritten to GROUP BY if skippable) | ||
| 1619 | { | ||
| 1620 | /* | ||
| 1621 | When there is SQL_BIG_RESULT or a JSON aggregation function, | ||
| 1622 | do not sort using index for GROUP BY, and thus force sorting on disk | ||
| 1623 | unless a group min-max optimization is going to be used as it is applied | ||
| 1624 | now only for one table queries with covering indexes. | ||
| 1625 | */ | ||
| 1626 |
8/8✓ Branch 0 taken 16065 times.
✓ Branch 1 taken 71 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 16005 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 129 times.
✓ Branch 6 taken 16007 times.
✓ Branch 7 taken 129 times.
|
16269 | if (!(query_block->active_options() & SELECT_BIG_RESULT || with_json_agg) || |
| 1627 | 131 | (tab->range_scan() && | |
| 1628 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | tab->range_scan()->type == AccessPath::GROUP_INDEX_SKIP_SCAN)) { |
| 1629 |
2/2✓ Branch 0 taken 14231 times.
✓ Branch 1 taken 1776 times.
|
16007 | if (simple_group && // GROUP BY is possibly skippable |
| 1630 |
2/2✓ Branch 0 taken 14110 times.
✓ Branch 1 taken 121 times.
|
14231 | !select_distinct) // .. if not preceded by a DISTINCT |
| 1631 | { | ||
| 1632 | /* | ||
| 1633 | Calculate a possible 'limit' of table rows for 'GROUP BY': | ||
| 1634 | A specified 'LIMIT' is relative to the final resultset. | ||
| 1635 | 'need_tmp' implies that there will be more postprocessing | ||
| 1636 | so the specified 'limit' should not be enforced yet. | ||
| 1637 | */ | ||
| 1638 | 14110 | const ha_rows limit = | |
| 1639 |
2/2✓ Branch 0 taken 406 times.
✓ Branch 1 taken 13704 times.
|
14110 | (need_tmp_before_win ? HA_POS_ERROR : m_select_limit); |
| 1640 | int dummy; | ||
| 1641 | |||
| 1642 |
2/2✓ Branch 0 taken 2894 times.
✓ Branch 1 taken 11216 times.
|
14110 | if (test_if_skip_sort_order(tab, group_list, limit, false, |
| 1643 |
1/2✓ Branch 0 taken 14110 times.
✗ Branch 1 not taken.
|
14110 | &tab->table()->keys_in_use_for_group_by, |
| 1644 | &dummy)) { | ||
| 1645 | 2894 | m_ordered_index_usage = ORDERED_INDEX_GROUP_BY; | |
| 1646 | } | ||
| 1647 | } | ||
| 1648 | |||
| 1649 | /* | ||
| 1650 | If we are going to use semi-join LooseScan, it will depend | ||
| 1651 | on the selected index scan to be used. If index is not used | ||
| 1652 | for the GROUP BY, we risk that sorting is put on the LooseScan | ||
| 1653 | table. In order to avoid this, force use of temporary table. | ||
| 1654 | TODO: Explain the allow_group_via_temp_table part of the test below. | ||
| 1655 | */ | ||
| 1656 |
4/4✓ Branch 0 taken 13113 times.
✓ Branch 1 taken 2894 times.
✓ Branch 2 taken 11551 times.
✓ Branch 3 taken 4456 times.
|
29120 | if ((m_ordered_index_usage != ORDERED_INDEX_GROUP_BY) && |
| 1657 |
2/2✓ Branch 0 taken 1562 times.
✓ Branch 1 taken 11551 times.
|
13113 | (tmp_table_param.allow_group_via_temp_table || |
| 1658 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1562 times.
|
1562 | (tab->emb_sj_nest && |
| 1659 | ✗ | tab->position()->sj_strategy == SJ_OPT_LOOSE_SCAN))) { | |
| 1660 | 11551 | need_tmp_before_win = true; | |
| 1661 | 11551 | simple_order = simple_group = false; // Force tmp table without sort | |
| 1662 | } | ||
| 1663 | } | ||
| 1664 | 1714843 | } else if (!order.empty() && // ORDER BY wo/ preceding GROUP BY | |
| 1665 |
2/2✓ Branch 0 taken 241833 times.
✓ Branch 1 taken 299516 times.
|
541349 | (simple_order || |
| 1666 |
5/6✓ Branch 0 taken 541349 times.
✓ Branch 1 taken 1173418 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 241833 times.
✓ Branch 4 taken 299433 times.
✓ Branch 5 taken 1415334 times.
|
2256116 | skip_sort_order) && // which is possibly skippable, |
| 1667 |
2/2✓ Branch 0 taken 299433 times.
✓ Branch 1 taken 83 times.
|
299516 | !m_windows_sort) // and WFs will not shuffle rows |
| 1668 | { | ||
| 1669 | int dummy; | ||
| 1670 |
2/2✓ Branch 0 taken 18555 times.
✓ Branch 1 taken 280878 times.
|
299433 | if ((skip_sort_order = test_if_skip_sort_order( |
| 1671 | 299433 | tab, order, m_select_limit, false, | |
| 1672 |
1/2✓ Branch 0 taken 299433 times.
✗ Branch 1 not taken.
|
299433 | &tab->table()->keys_in_use_for_order_by, &dummy))) { |
| 1673 | 18555 | m_ordered_index_usage = ORDERED_INDEX_ORDER_BY; | |
| 1674 | } | ||
| 1675 | } | ||
| 1676 | 1730903 | } | |
| 1677 | |||
| 1678 | /** | ||
| 1679 | Test if ORDER BY is a single MATCH function(ORDER BY MATCH) | ||
| 1680 | and sort order is descending. | ||
| 1681 | |||
| 1682 | @param order pointer to ORDER struct. | ||
| 1683 | |||
| 1684 | @retval | ||
| 1685 | Pointer to MATCH function if order is 'ORDER BY MATCH() DESC' | ||
| 1686 | @retval | ||
| 1687 | NULL otherwise | ||
| 1688 | */ | ||
| 1689 | |||
| 1690 | 299897 | static Item_func_match *test_if_ft_index_order(ORDER *order) { | |
| 1691 |
7/8✓ Branch 0 taken 299897 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 229620 times.
✓ Branch 3 taken 70277 times.
✓ Branch 4 taken 4080 times.
✓ Branch 5 taken 225540 times.
✓ Branch 6 taken 72 times.
✓ Branch 7 taken 299825 times.
|
303977 | if (order && order->next == nullptr && order->direction == ORDER_DESC && |
| 1692 |
2/2✓ Branch 0 taken 72 times.
✓ Branch 1 taken 4008 times.
|
4080 | is_function_of_type(*order->item, Item_func::FT_FUNC)) |
| 1693 | 72 | return down_cast<Item_func_match *>(*order->item)->get_master(); | |
| 1694 | |||
| 1695 | 299825 | return nullptr; | |
| 1696 | } | ||
| 1697 | |||
| 1698 | /** | ||
| 1699 | Test if this is a prefix index. | ||
| 1700 | |||
| 1701 | @param table table | ||
| 1702 | @param idx index to check | ||
| 1703 | |||
| 1704 | @return TRUE if this is a prefix index | ||
| 1705 | */ | ||
| 1706 | 64 | bool is_prefix_index(TABLE *table, uint idx) { | |
| 1707 |
2/4✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
|
64 | if (!table || !table->key_info) { |
| 1708 | ✗ | return false; | |
| 1709 | } | ||
| 1710 | |||
| 1711 | 64 | KEY *key_info = table->key_info; | |
| 1712 | 64 | uint key_parts = key_info[idx].user_defined_key_parts; | |
| 1713 | 64 | KEY_PART_INFO *key_part = key_info[idx].key_part; | |
| 1714 | |||
| 1715 |
2/2✓ Branch 0 taken 130 times.
✓ Branch 1 taken 62 times.
|
192 | for (uint i = 0; i < key_parts; i++, key_part++) { |
| 1716 | 390 | if (key_part->field && | |
| 1717 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 128 times.
|
130 | !(table->field[key_part->fieldnr - 1] |
| 1718 |
3/4✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 128 times.
|
260 | ->part_of_prefixkey.is_clear_all()) && |
| 1719 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | !(key_info->flags & (HA_FULLTEXT | HA_SPATIAL))) { |
| 1720 | 2 | return true; | |
| 1721 | } | ||
| 1722 | } | ||
| 1723 | 62 | return false; | |
| 1724 | } | ||
| 1725 | |||
| 1726 | /** | ||
| 1727 | Test if one can use the key to resolve ordering. | ||
| 1728 | |||
| 1729 | @param order_src Sort order | ||
| 1730 | @param table Table to sort | ||
| 1731 | @param idx Index to check | ||
| 1732 | @param[out] used_key_parts NULL by default, otherwise return value for | ||
| 1733 | used key parts. | ||
| 1734 | @param[out] skip_quick Whether found index can be used for backward range | ||
| 1735 | scans | ||
| 1736 | |||
| 1737 | @note | ||
| 1738 | used_key_parts is set to correct key parts used if return value != 0 | ||
| 1739 | (On other cases, used_key_part may be changed) | ||
| 1740 | Note that the value may actually be greater than the number of index | ||
| 1741 | key parts. This can happen for storage engines that have the primary | ||
| 1742 | key parts as a suffix for every secondary key. | ||
| 1743 | |||
| 1744 | @retval | ||
| 1745 | 1 key is ok. | ||
| 1746 | @retval | ||
| 1747 | 0 Key can't be used | ||
| 1748 | @retval | ||
| 1749 | -1 Reverse key can be used | ||
| 1750 | */ | ||
| 1751 | |||
| 1752 | 65408 | int test_if_order_by_key(ORDER_with_src *order_src, TABLE *table, uint idx, | |
| 1753 | uint *used_key_parts, bool *skip_quick) { | ||
| 1754 |
1/2✓ Branch 0 taken 65408 times.
✗ Branch 1 not taken.
|
65408 | DBUG_TRACE; |
| 1755 | KEY_PART_INFO *key_part, *key_part_end; | ||
| 1756 | 65408 | key_part = table->key_info[idx].key_part; | |
| 1757 | 65408 | key_part_end = key_part + table->key_info[idx].user_defined_key_parts; | |
| 1758 | 65408 | key_part_map const_key_parts = table->const_key_parts[idx]; | |
| 1759 | 65408 | int reverse = 0; | |
| 1760 | uint key_parts; | ||
| 1761 | 65408 | bool on_pk_suffix = false; | |
| 1762 | // Whether [extended] key has key parts with mixed ASC/DESC order | ||
| 1763 | 65408 | bool mixed_order = false; | |
| 1764 | // Order direction of the first key part | ||
| 1765 | 65408 | bool reverse_sorted = (bool)(key_part->key_part_flag & HA_REVERSE_SORT); | |
| 1766 | 65408 | ORDER *order = order_src->order; | |
| 1767 | 65408 | *skip_quick = false; | |
| 1768 | |||
| 1769 |
2/2✓ Branch 0 taken 73700 times.
✓ Branch 1 taken 54604 times.
|
128304 | for (; order; order = order->next, const_key_parts >>= 1) { |
| 1770 | /* | ||
| 1771 | Since only fields can be indexed, ORDER BY <something> that is | ||
| 1772 | not a field cannot be resolved by using an index. | ||
| 1773 | */ | ||
| 1774 |
1/2✓ Branch 0 taken 73700 times.
✗ Branch 1 not taken.
|
73700 | Item *real_itm = (*order->item)->real_item(); |
| 1775 |
3/4✓ Branch 0 taken 73700 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 73674 times.
|
73700 | if (real_itm->type() != Item::FIELD_ITEM) return 0; |
| 1776 | |||
| 1777 | 73674 | const Field *field = down_cast<const Item_field *>(real_itm)->field; | |
| 1778 | |||
| 1779 | /* | ||
| 1780 | Skip key parts that are constants in the WHERE clause. | ||
| 1781 | These are already skipped in the ORDER BY by check_field_is_const() | ||
| 1782 | */ | ||
| 1783 |
4/4✓ Branch 0 taken 3753 times.
✓ Branch 1 taken 73668 times.
✓ Branch 2 taken 3747 times.
✓ Branch 3 taken 6 times.
|
77421 | for (; const_key_parts & 1 && key_part < key_part_end; |
| 1784 | 3747 | const_key_parts >>= 1) | |
| 1785 | 3747 | key_part++; | |
| 1786 | |||
| 1787 | /* Avoid usage of prefix index for sorting a partition table */ | ||
| 1788 |
4/4✓ Branch 0 taken 69 times.
✓ Branch 1 taken 1606 times.
✓ Branch 2 taken 64 times.
✓ Branch 3 taken 5 times.
|
1675 | if (table->part_info && key_part != table->key_info[idx].key_part && |
| 1789 |
7/8✓ Branch 0 taken 1675 times.
✓ Branch 1 taken 71999 times.
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 62 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 73672 times.
|
75349 | key_part != key_part_end && is_prefix_index(table, idx)) |
| 1790 | 2 | return 0; | |
| 1791 | |||
| 1792 |
2/2✓ Branch 0 taken 632 times.
✓ Branch 1 taken 73040 times.
|
73672 | if (key_part == key_part_end) { |
| 1793 | /* | ||
| 1794 | We are at the end of the key. Check if the engine has the primary | ||
| 1795 | key as a suffix to the secondary keys. If it has continue to check | ||
| 1796 | the primary key as a suffix. | ||
| 1797 | */ | ||
| 1798 | 1896 | if (!on_pk_suffix && | |
| 1799 |
2/2✓ Branch 0 taken 615 times.
✓ Branch 1 taken 17 times.
|
632 | (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && |
| 1800 |
7/8✓ Branch 0 taken 632 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 395 times.
✓ Branch 3 taken 220 times.
✓ Branch 4 taken 343 times.
✓ Branch 5 taken 52 times.
✓ Branch 6 taken 343 times.
✓ Branch 7 taken 289 times.
|
1264 | table->s->primary_key != MAX_KEY && table->s->primary_key != idx) { |
| 1801 | 343 | on_pk_suffix = true; | |
| 1802 | 343 | key_part = table->key_info[table->s->primary_key].key_part; | |
| 1803 | 343 | key_part_end = | |
| 1804 | 343 | key_part + | |
| 1805 | 343 | table->key_info[table->s->primary_key].user_defined_key_parts; | |
| 1806 | 343 | const_key_parts = table->const_key_parts[table->s->primary_key]; | |
| 1807 | |||
| 1808 |
3/4✓ Branch 0 taken 9 times.
✓ Branch 1 taken 343 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
|
352 | for (; const_key_parts & 1 && key_part < key_part_end; |
| 1809 | 9 | const_key_parts >>= 1) | |
| 1810 | 9 | key_part++; | |
| 1811 | /* | ||
| 1812 | The primary and secondary key parts were all const (i.e. there's | ||
| 1813 | one row). The sorting doesn't matter. | ||
| 1814 | */ | ||
| 1815 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 343 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
343 | if (key_part == key_part_end && reverse == 0) { |
| 1816 | ✗ | key_parts = 0; | |
| 1817 | ✗ | reverse = 1; | |
| 1818 | ✗ | goto ok; | |
| 1819 | } | ||
| 1820 | } else | ||
| 1821 | 289 | return 0; | |
| 1822 | } | ||
| 1823 | |||
| 1824 |
6/6✓ Branch 0 taken 67183 times.
✓ Branch 1 taken 6200 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 67153 times.
✓ Branch 4 taken 6230 times.
✓ Branch 5 taken 67153 times.
|
73383 | if (key_part->field != field || !field->part_of_sortkey.is_set(idx)) |
| 1825 | 6230 | return 0; | |
| 1826 |
2/2✓ Branch 0 taken 63457 times.
✓ Branch 1 taken 3696 times.
|
67153 | if (order->direction != ORDER_NOT_RELEVANT) { |
| 1827 | 63457 | const enum_order keypart_order = | |
| 1828 |
2/2✓ Branch 0 taken 176 times.
✓ Branch 1 taken 63281 times.
|
63457 | (key_part->key_part_flag & HA_REVERSE_SORT) ? ORDER_DESC : ORDER_ASC; |
| 1829 | /* set flag to 1 if we can use read-next on key, else to -1 */ | ||
| 1830 |
2/2✓ Branch 0 taken 52571 times.
✓ Branch 1 taken 10886 times.
|
63457 | int cur_scan_dir = (order->direction == keypart_order) ? 1 : -1; |
| 1831 |
4/4✓ Branch 0 taken 7844 times.
✓ Branch 1 taken 55613 times.
✓ Branch 2 taken 4257 times.
✓ Branch 3 taken 3587 times.
|
63457 | if (reverse && cur_scan_dir != reverse) return 0; |
| 1832 | 59200 | reverse = cur_scan_dir; // Remember if reverse | |
| 1833 | } | ||
| 1834 | 62896 | mixed_order |= | |
| 1835 | 62896 | (reverse_sorted != (bool)((key_part)->key_part_flag & HA_REVERSE_SORT)); | |
| 1836 | |||
| 1837 | 62896 | key_part++; | |
| 1838 | } | ||
| 1839 | /* | ||
| 1840 | The index picked here might be used for range scans with multiple ranges. | ||
| 1841 | This will require tricky reordering in case of ranges would have to be | ||
| 1842 | scanned backward and index consists of mixed ASC/DESC key parts. Due to that | ||
| 1843 | backward scans on such indexes are disabled. | ||
| 1844 | */ | ||
| 1845 |
4/4✓ Branch 0 taken 165 times.
✓ Branch 1 taken 54439 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 130 times.
|
54604 | if (mixed_order && reverse < 0) *skip_quick = true; |
| 1846 | |||
| 1847 |
2/2✓ Branch 0 taken 3577 times.
✓ Branch 1 taken 51027 times.
|
54604 | if (!reverse) { |
| 1848 | /* | ||
| 1849 | We get here when the key is suitable and we don't care about it's | ||
| 1850 | order, i.e. GROUP BY/DISTINCT. Use forward scan. | ||
| 1851 | */ | ||
| 1852 | 3577 | reverse = 1; | |
| 1853 | } | ||
| 1854 |
2/2✓ Branch 0 taken 198 times.
✓ Branch 1 taken 54406 times.
|
54604 | if (on_pk_suffix) { |
| 1855 | 198 | uint used_key_parts_secondary = table->key_info[idx].user_defined_key_parts; | |
| 1856 | 198 | uint used_key_parts_pk = | |
| 1857 | 198 | (uint)(key_part - table->key_info[table->s->primary_key].key_part); | |
| 1858 | 198 | key_parts = used_key_parts_pk + used_key_parts_secondary; | |
| 1859 | |||
| 1860 |
3/4✓ Branch 0 taken 122 times.
✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 198 times.
|
320 | if (reverse == -1 && |
| 1861 |
2/4✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 122 times.
✗ Branch 3 not taken.
|
122 | (!(table->file->index_flags(idx, used_key_parts_secondary - 1, true) & |
| 1862 | 122 | HA_READ_PREV) || | |
| 1863 |
1/2✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
|
122 | !(table->file->index_flags(table->s->primary_key, |
| 1864 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
|
122 | used_key_parts_pk - 1, true) & |
| 1865 | HA_READ_PREV))) | ||
| 1866 | ✗ | reverse = 0; // Index can't be used | |
| 1867 | } else { | ||
| 1868 | 54406 | key_parts = (uint)(key_part - table->key_info[idx].key_part); | |
| 1869 |
3/4✓ Branch 0 taken 6307 times.
✓ Branch 1 taken 48099 times.
✓ Branch 2 taken 54406 times.
✗ Branch 3 not taken.
|
60713 | if (reverse == -1 && |
| 1870 |
2/4✓ Branch 0 taken 6307 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6307 times.
|
6307 | !(table->file->index_flags(idx, key_parts - 1, true) & HA_READ_PREV)) |
| 1871 | ✗ | reverse = 0; // Index can't be used | |
| 1872 | } | ||
| 1873 | 54406 | ok: | |
| 1874 |
2/2✓ Branch 0 taken 53233 times.
✓ Branch 1 taken 1371 times.
|
54604 | if (used_key_parts != nullptr) *used_key_parts = key_parts; |
| 1875 | 54604 | return reverse; | |
| 1876 | 65408 | } | |
| 1877 | |||
| 1878 | /** | ||
| 1879 | Find shortest key suitable for full table scan. | ||
| 1880 | |||
| 1881 | @param table Table to scan | ||
| 1882 | @param usable_keys Allowed keys | ||
| 1883 | |||
| 1884 | @note | ||
| 1885 | As far as | ||
| 1886 | 1) clustered primary key entry data set is a set of all record | ||
| 1887 | fields (key fields and not key fields) and | ||
| 1888 | 2) secondary index entry data is a union of its key fields and | ||
| 1889 | primary key fields (at least InnoDB and its derivatives don't | ||
| 1890 | duplicate primary key fields there, even if the primary and | ||
| 1891 | the secondary keys have a common subset of key fields), | ||
| 1892 | then secondary index entry data is always a subset of primary key entry. | ||
| 1893 | Unfortunately, key_info[nr].key_length doesn't show the length | ||
| 1894 | of key/pointer pair but a sum of key field lengths only, thus | ||
| 1895 | we can't estimate index IO volume comparing only this key_length | ||
| 1896 | value of secondary keys and clustered PK. | ||
| 1897 | So, try secondary keys first, and choose PK only if there are no | ||
| 1898 | usable secondary covering keys or found best secondary key include | ||
| 1899 | all table fields (i.e. same as PK): | ||
| 1900 | |||
| 1901 | @return | ||
| 1902 | MAX_KEY no suitable key found | ||
| 1903 | key index otherwise | ||
| 1904 | */ | ||
| 1905 | |||
| 1906 | 1750115 | uint find_shortest_key(TABLE *table, const Key_map *usable_keys) { | |
| 1907 | 1750115 | uint best = MAX_KEY; | |
| 1908 | 1750115 | uint usable_clustered_pk = (table->file->primary_key_is_clustered() && | |
| 1909 |
4/4✓ Branch 0 taken 714920 times.
✓ Branch 1 taken 372665 times.
✓ Branch 2 taken 359335 times.
✓ Branch 3 taken 355555 times.
|
1802475 | table->s->primary_key != MAX_KEY && |
| 1910 | 714920 | usable_keys->is_set(table->s->primary_key)) | |
| 1911 |
2/2✓ Branch 0 taken 1087585 times.
✓ Branch 1 taken 662632 times.
|
2837772 | ? table->s->primary_key |
| 1912 | 1750187 | : MAX_KEY; | |
| 1913 |
2/2✓ Branch 0 taken 548313 times.
✓ Branch 1 taken 1201888 times.
|
1750187 | if (!usable_keys->is_clear_all()) { |
| 1914 | 548313 | uint min_length = (uint)~0; | |
| 1915 |
2/2✓ Branch 0 taken 953055 times.
✓ Branch 1 taken 548319 times.
|
1501374 | for (uint nr = 0; nr < table->s->keys; nr++) { |
| 1916 |
2/2✓ Branch 0 taken 359329 times.
✓ Branch 1 taken 593726 times.
|
953055 | if (nr == usable_clustered_pk) continue; |
| 1917 |
2/2✓ Branch 0 taken 433041 times.
✓ Branch 1 taken 160691 times.
|
593726 | if (usable_keys->is_set(nr)) { |
| 1918 | /* | ||
| 1919 | Can not do full index scan on rtree index because it is not | ||
| 1920 | supported by Innodb, probably not supported by others either. | ||
| 1921 | A multi-valued key requires unique filter, and won't be the most | ||
| 1922 | fast option even if it will be the shortest one. | ||
| 1923 | */ | ||
| 1924 | 433041 | const KEY &key_ref = table->key_info[nr]; | |
| 1925 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 433041 times.
|
433041 | assert(!(key_ref.flags & HA_MULTI_VALUED_KEY)); |
| 1926 |
4/4✓ Branch 0 taken 426627 times.
✓ Branch 1 taken 6414 times.
✓ Branch 2 taken 426251 times.
✓ Branch 3 taken 376 times.
|
433041 | if (key_ref.key_length < min_length && !(key_ref.flags & HA_SPATIAL)) { |
| 1927 | 426251 | min_length = key_ref.key_length; | |
| 1928 | 426251 | best = nr; | |
| 1929 | } | ||
| 1930 | } | ||
| 1931 | } | ||
| 1932 | } | ||
| 1933 |
2/2✓ Branch 0 taken 359356 times.
✓ Branch 1 taken 1390851 times.
|
1750207 | if (usable_clustered_pk != MAX_KEY) { |
| 1934 | /* | ||
| 1935 | If the primary key is clustered and found shorter key covers all table | ||
| 1936 | fields and is not clustering then primary key scan normally would be | ||
| 1937 | faster because amount of data to scan is the same but PK is clustered. | ||
| 1938 | It's safe to compare key parts with table fields since duplicate key | ||
| 1939 | parts aren't allowed. | ||
| 1940 | */ | ||
| 1941 |
4/4✓ Branch 0 taken 236829 times.
✓ Branch 1 taken 122527 times.
✓ Branch 2 taken 122609 times.
✓ Branch 3 taken 236747 times.
|
596185 | if (best == MAX_KEY || |
| 1942 |
2/2✓ Branch 0 taken 76 times.
✓ Branch 1 taken 236753 times.
|
236829 | ((table->key_info[best].user_defined_key_parts >= table->s->fields) && |
| 1943 |
1/2✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
|
76 | !(table->file->index_flags(best, 0, 0) & HA_CLUSTERED_INDEX))) |
| 1944 | 122609 | best = usable_clustered_pk; | |
| 1945 | } | ||
| 1946 | 1750207 | return best; | |
| 1947 | } | ||
| 1948 | |||
| 1949 | /** | ||
| 1950 | Test if a second key is the subkey of the first one. | ||
| 1951 | |||
| 1952 | @param key_part First key parts | ||
| 1953 | @param ref_key_part Second key parts | ||
| 1954 | @param ref_key_part_end Last+1 part of the second key | ||
| 1955 | |||
| 1956 | @note | ||
| 1957 | Second key MUST be shorter than the first one. | ||
| 1958 | |||
| 1959 | @retval | ||
| 1960 | 1 is a subkey | ||
| 1961 | @retval | ||
| 1962 | 0 no sub key | ||
| 1963 | */ | ||
| 1964 | |||
| 1965 | 1207 | inline bool is_subkey(KEY_PART_INFO *key_part, KEY_PART_INFO *ref_key_part, | |
| 1966 | KEY_PART_INFO *ref_key_part_end) { | ||
| 1967 |
2/2✓ Branch 0 taken 1207 times.
✓ Branch 1 taken 384 times.
|
1591 | for (; ref_key_part < ref_key_part_end; key_part++, ref_key_part++) |
| 1968 |
2/2✓ Branch 0 taken 823 times.
✓ Branch 1 taken 384 times.
|
1207 | if (!key_part->field->eq(ref_key_part->field)) return false; |
| 1969 | 384 | return true; | |
| 1970 | } | ||
| 1971 | |||
| 1972 | /** | ||
| 1973 | Test if REF_OR_NULL optimization will be used if the specified | ||
| 1974 | ref_key is used for REF-access to 'tab' | ||
| 1975 | |||
| 1976 | @retval | ||
| 1977 | true JT_REF_OR_NULL will be used | ||
| 1978 | @retval | ||
| 1979 | false no JT_REF_OR_NULL access | ||
| 1980 | */ | ||
| 1981 | |||
| 1982 | 384 | static bool is_ref_or_null_optimized(const JOIN_TAB *tab, uint ref_key) { | |
| 1983 |
2/2✓ Branch 0 taken 363 times.
✓ Branch 1 taken 21 times.
|
384 | if (tab->keyuse()) { |
| 1984 | 363 | const Key_use *keyuse = tab->keyuse(); | |
| 1985 |
3/4✓ Branch 0 taken 315 times.
✓ Branch 1 taken 363 times.
✓ Branch 2 taken 315 times.
✗ Branch 3 not taken.
|
678 | while (keyuse->key != ref_key && keyuse->table_ref == tab->table_ref) |
| 1986 | 315 | keyuse++; | |
| 1987 | |||
| 1988 | 363 | const table_map const_tables = tab->join()->const_table_map; | |
| 1989 |
3/4✓ Branch 0 taken 395 times.
✓ Branch 1 taken 331 times.
✓ Branch 2 taken 395 times.
✗ Branch 3 not taken.
|
726 | while (keyuse->key == ref_key && keyuse->table_ref == tab->table_ref) { |
| 1990 |
2/2✓ Branch 0 taken 377 times.
✓ Branch 1 taken 18 times.
|
395 | if (!(keyuse->used_tables & ~const_tables)) { |
| 1991 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 345 times.
|
377 | if (keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL) return true; |
| 1992 | } | ||
| 1993 | 363 | keyuse++; | |
| 1994 | } | ||
| 1995 | } | ||
| 1996 | 352 | return false; | |
| 1997 | } | ||
| 1998 | |||
| 1999 | /** | ||
| 2000 | Test if we can use one of the 'usable_keys' instead of 'ref' key | ||
| 2001 | for sorting. | ||
| 2002 | |||
| 2003 | @param order The query block's order clause. | ||
| 2004 | @param tab Current JOIN_TAB. | ||
| 2005 | @param ref Number of key, used for WHERE clause | ||
| 2006 | @param ref_key_parts Index columns used for ref lookup. | ||
| 2007 | @param usable_keys Keys for testing | ||
| 2008 | |||
| 2009 | @return | ||
| 2010 | - MAX_KEY If we can't use other key | ||
| 2011 | - the number of found key Otherwise | ||
| 2012 | */ | ||
| 2013 | |||
| 2014 | 1183 | static uint test_if_subkey(ORDER_with_src *order, JOIN_TAB *tab, uint ref, | |
| 2015 | uint ref_key_parts, const Key_map *usable_keys) { | ||
| 2016 | uint nr; | ||
| 2017 | 1183 | uint min_length = (uint)~0; | |
| 2018 | 1183 | uint best = MAX_KEY; | |
| 2019 | 1183 | TABLE *table = tab->table(); | |
| 2020 | 1183 | KEY_PART_INFO *ref_key_part = table->key_info[ref].key_part; | |
| 2021 | 1183 | KEY_PART_INFO *ref_key_part_end = ref_key_part + ref_key_parts; | |
| 2022 | |||
| 2023 |
2/2✓ Branch 0 taken 3532 times.
✓ Branch 1 taken 1183 times.
|
4715 | for (nr = 0; nr < table->s->keys; nr++) { |
| 2024 | bool skip_quick; | ||
| 2025 | 3532 | if (usable_keys->is_set(nr) && | |
| 2026 |
2/2✓ Branch 0 taken 1207 times.
✓ Branch 1 taken 2 times.
|
1209 | table->key_info[nr].key_length < min_length && |
| 2027 |
1/2✓ Branch 0 taken 1207 times.
✗ Branch 1 not taken.
|
1207 | table->key_info[nr].user_defined_key_parts >= ref_key_parts && |
| 2028 |
3/4✓ Branch 0 taken 1207 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 384 times.
✓ Branch 3 taken 823 times.
|
1207 | is_subkey(table->key_info[nr].key_part, ref_key_part, |
| 2029 | 384 | ref_key_part_end) && | |
| 2030 |
2/2✓ Branch 0 taken 352 times.
✓ Branch 1 taken 32 times.
|
384 | !is_ref_or_null_optimized(tab, nr) && |
| 2031 |
7/8✓ Branch 0 taken 1209 times.
✓ Branch 1 taken 2323 times.
✓ Branch 2 taken 352 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 347 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 347 times.
✓ Branch 7 taken 3185 times.
|
5088 | test_if_order_by_key(order, table, nr, nullptr, &skip_quick) && |
| 2032 |
1/2✓ Branch 0 taken 347 times.
✗ Branch 1 not taken.
|
347 | !skip_quick) { |
| 2033 | 347 | min_length = table->key_info[nr].key_length; | |
| 2034 | 347 | best = nr; | |
| 2035 | } | ||
| 2036 | } | ||
| 2037 | 1183 | return best; | |
| 2038 | } | ||
| 2039 | |||
| 2040 | /** | ||
| 2041 | It is not obvious to see that test_if_skip_sort_order() never changes the | ||
| 2042 | plan if no_changes is true. So we double-check: creating an instance of this | ||
| 2043 | class saves some important access-path-related information of the current | ||
| 2044 | table; when the instance is destroyed, the latest access-path information is | ||
| 2045 | compared with saved data. | ||
| 2046 | */ | ||
| 2047 | |||
| 2048 | class Plan_change_watchdog { | ||
| 2049 | #ifndef NDEBUG | ||
| 2050 | public: | ||
| 2051 | /** | ||
| 2052 | @param tab_arg table whose access path is being determined | ||
| 2053 | @param no_changes_arg whether a change to the access path is allowed | ||
| 2054 | */ | ||
| 2055 | 313823 | Plan_change_watchdog(const JOIN_TAB *tab_arg, const bool no_changes_arg) { | |
| 2056 |
2/2✓ Branch 0 taken 280 times.
✓ Branch 1 taken 313543 times.
|
313823 | if (no_changes_arg) { |
| 2057 | 280 | tab = tab_arg; | |
| 2058 | 280 | type = tab->type(); | |
| 2059 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 271 times.
|
280 | if ((quick = tab->range_scan())) quick_index = used_index(quick); |
| 2060 | 280 | use_quick = tab->use_quick; | |
| 2061 | 280 | ref_key = tab->ref().key; | |
| 2062 | 280 | ref_key_parts = tab->ref().key_parts; | |
| 2063 | 280 | index = tab->index(); | |
| 2064 | } else { | ||
| 2065 | 313543 | tab = nullptr; | |
| 2066 | 313543 | type = JT_UNKNOWN; | |
| 2067 | 313543 | quick = nullptr; | |
| 2068 | 313543 | ref_key = ref_key_parts = index = 0; | |
| 2069 | 313543 | use_quick = QS_NONE; | |
| 2070 | } | ||
| 2071 | 313823 | } | |
| 2072 | 314103 | ~Plan_change_watchdog() { | |
| 2073 |
2/2✓ Branch 0 taken 313543 times.
✓ Branch 1 taken 280 times.
|
313823 | if (tab == nullptr) return; |
| 2074 | // changes are not allowed, we verify: | ||
| 2075 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
|
280 | assert(tab->type() == type); |
| 2076 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
|
280 | assert(tab->range_scan() == quick); |
| 2077 |
3/4✓ Branch 0 taken 9 times.
✓ Branch 1 taken 271 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
|
280 | assert(quick == nullptr || used_index(tab->range_scan()) == quick_index); |
| 2078 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
|
280 | assert(tab->use_quick == use_quick); |
| 2079 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
|
280 | assert(tab->ref().key == ref_key); |
| 2080 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
|
280 | assert(tab->ref().key_parts == ref_key_parts); |
| 2081 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
|
280 | assert(tab->index() == index); |
| 2082 | 313823 | } | |
| 2083 | |||
| 2084 | private: | ||
| 2085 | const JOIN_TAB *tab; ///< table, or NULL if changes are allowed | ||
| 2086 | enum join_type type; ///< copy of tab->type() | ||
| 2087 | // "Range / index merge" info | ||
| 2088 | const AccessPath *quick{nullptr}; ///< copy of tab->select->quick | ||
| 2089 | uint quick_index{0}; ///< copy of tab->select->quick->index | ||
| 2090 | enum quick_type use_quick; ///< copy of tab->use_quick | ||
| 2091 | // "ref access" info | ||
| 2092 | int ref_key; ///< copy of tab->ref().key | ||
| 2093 | uint ref_key_parts; /// copy of tab->ref().key_parts | ||
| 2094 | // Other index-related info | ||
| 2095 | uint index; ///< copy of tab->index | ||
| 2096 | #else // in non-debug build, empty class | ||
| 2097 | public: | ||
| 2098 | Plan_change_watchdog(const JOIN_TAB *, const bool) {} | ||
| 2099 | #endif | ||
| 2100 | }; | ||
| 2101 | |||
| 2102 | /** | ||
| 2103 | Test if we can skip ordering by using an index. | ||
| 2104 | |||
| 2105 | If the current plan is to use an index that provides ordering, the | ||
| 2106 | plan will not be changed. Otherwise, if an index can be used, the | ||
| 2107 | JOIN_TAB / tab->select struct is changed to use the index. | ||
| 2108 | |||
| 2109 | The index must cover all fields in @<order@>, or it will not be considered. | ||
| 2110 | |||
| 2111 | @param tab NULL or JOIN_TAB of the accessed table | ||
| 2112 | @param order Linked list of ORDER BY arguments | ||
| 2113 | @param select_limit LIMIT value, or HA_POS_ERROR if no limit | ||
| 2114 | @param no_changes No changes will be made to the query plan. | ||
| 2115 | @param map Key_map of applicable indexes. | ||
| 2116 | @param [out] order_idx Number of index selected, -1 if no applicable index | ||
| 2117 | found | ||
| 2118 | |||
| 2119 | @todo | ||
| 2120 | - sergeyp: Results of all index merge selects actually are ordered | ||
| 2121 | by clustered PK values. | ||
| 2122 | |||
| 2123 | @note | ||
| 2124 | This function may change tmp_table_param.precomputed_group_by. This | ||
| 2125 | affects how create_tmp_table() treats aggregation functions, so | ||
| 2126 | count_field_types() must be called again to make sure this is taken | ||
| 2127 | into consideration. | ||
| 2128 | |||
| 2129 | @retval | ||
| 2130 | 0 We have to use filesort to do the sorting | ||
| 2131 | @retval | ||
| 2132 | 1 We can use an index. | ||
| 2133 | */ | ||
| 2134 | |||
| 2135 | 313823 | static bool test_if_skip_sort_order(JOIN_TAB *tab, ORDER_with_src &order, | |
| 2136 | ha_rows select_limit, const bool no_changes, | ||
| 2137 | const Key_map *map, int *order_idx) { | ||
| 2138 |
1/2✓ Branch 0 taken 313823 times.
✗ Branch 1 not taken.
|
313823 | DBUG_TRACE; |
| 2139 | int ref_key; | ||
| 2140 | 313823 | uint ref_key_parts = 0; | |
| 2141 | 313823 | int order_direction = 0; | |
| 2142 | 313823 | uint used_key_parts = 0; | |
| 2143 | 313823 | TABLE *const table = tab->table(); | |
| 2144 | 313823 | JOIN *const join = tab->join(); | |
| 2145 | 313823 | THD *const thd = join->thd; | |
| 2146 | 313823 | AccessPath *const save_range_scan = tab->range_scan(); | |
| 2147 | 313823 | int best_key = -1; | |
| 2148 | 313823 | bool set_up_ref_access_to_key = false; | |
| 2149 | 313823 | bool can_skip_sorting = false; // used as return value | |
| 2150 | 313823 | int changed_key = -1; | |
| 2151 | |||
| 2152 | /* Check that we are always called with first non-const table */ | ||
| 2153 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 313823 times.
|
313823 | assert((uint)tab->idx() == join->const_tables); |
| 2154 | |||
| 2155 | 313823 | Plan_change_watchdog watchdog(tab, no_changes); | |
| 2156 | 313823 | *order_idx = -1; | |
| 2157 | /* Sorting a single row can always be skipped */ | ||
| 2158 |
7/8✓ Branch 0 taken 313814 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 313813 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 313813 times.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 313813 times.
|
627636 | if (tab->type() == JT_EQ_REF || tab->type() == JT_CONST || |
| 2159 | 313813 | tab->type() == JT_SYSTEM) { | |
| 2160 | 10 | return true; | |
| 2161 | } | ||
| 2162 | |||
| 2163 | /* | ||
| 2164 | Check if FT index can be used to retrieve result in the required order. | ||
| 2165 | It is possible if ordering is on the first non-constant table. | ||
| 2166 | */ | ||
| 2167 |
6/6✓ Branch 0 taken 300085 times.
✓ Branch 1 taken 13728 times.
✓ Branch 2 taken 299833 times.
✓ Branch 3 taken 252 times.
✓ Branch 4 taken 299833 times.
✓ Branch 5 taken 13980 times.
|
313813 | if (!join->order.empty() && join->simple_order) { |
| 2168 | /* | ||
| 2169 | Check if ORDER is DESC, ORDER BY is a single MATCH function. | ||
| 2170 | */ | ||
| 2171 |
1/2✓ Branch 0 taken 299833 times.
✗ Branch 1 not taken.
|
299833 | Item_func_match *ft_func = test_if_ft_index_order(order.order); |
| 2172 | /* | ||
| 2173 | Two possible cases when we can skip sort order: | ||
| 2174 | 1. FT_SORTED must be set(Natural mode, no ORDER BY). | ||
| 2175 | 2. If FT_SORTED flag is not set then | ||
| 2176 | the engine should support deferred sorting. Deferred sorting means | ||
| 2177 | that sorting is postponed utill the start of index reading(InnoDB). | ||
| 2178 | In this case we set FT_SORTED flag here to let the engine know that | ||
| 2179 | internal sorting is needed. | ||
| 2180 | */ | ||
| 2181 |
9/10✓ Branch 0 taken 51 times.
✓ Branch 1 taken 299782 times.
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 49 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 45 times.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 45 times.
✓ Branch 9 taken 299788 times.
|
299833 | if (ft_func && ft_func->ft_handler && ft_func->ordered_result()) { |
| 2182 | /* | ||
| 2183 | FT index scan is used, so the only additional requirement is | ||
| 2184 | that ORDER BY MATCH function is the same as the function that | ||
| 2185 | is used for FT index. | ||
| 2186 | */ | ||
| 2187 |
4/4✓ Branch 0 taken 26 times.
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 24 times.
|
71 | if (tab->type() == JT_FT && |
| 2188 |
3/4✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 5 times.
|
26 | ft_func->eq(tab->position()->key->val, true)) { |
| 2189 |
1/2✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
|
21 | ft_func->set_hints(join, FT_SORTED, select_limit, false); |
| 2190 | 21 | return true; | |
| 2191 | } | ||
| 2192 | /* | ||
| 2193 | No index is used, it's possible to use FT index for ORDER BY if | ||
| 2194 | LIMIT is present and does not exceed count of the records in FT index | ||
| 2195 | and there is no WHERE condition since a condition may potentially | ||
| 2196 | require more rows to be fetch from FT index. | ||
| 2197 | */ | ||
| 2198 |
6/6✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 14 times.
|
36 | if (!tab->condition() && select_limit != HA_POS_ERROR && |
| 2199 |
3/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 2 times.
|
12 | select_limit <= ft_func->get_count()) { |
| 2200 | /* test_if_ft_index_order() always returns master MATCH function. */ | ||
| 2201 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | assert(!ft_func->master); |
| 2202 | /* ref is not set since there is no WHERE condition */ | ||
| 2203 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | assert(tab->ref().key == -1); |
| 2204 | |||
| 2205 | /*Make EXPLAIN happy */ | ||
| 2206 | 10 | tab->set_type(JT_FT); | |
| 2207 | 10 | tab->ref().key = ft_func->key; | |
| 2208 | 10 | tab->ref().key_parts = 0; | |
| 2209 | 10 | tab->set_index(ft_func->key); | |
| 2210 | 10 | tab->set_ft_func(ft_func); | |
| 2211 | |||
| 2212 | /* Setup FT handler */ | ||
| 2213 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | ft_func->set_hints(join, FT_SORTED, select_limit, true); |
| 2214 | 10 | ft_func->score_from_index_scan = true; | |
| 2215 | 10 | table->file->ft_handler = ft_func->ft_handler; | |
| 2216 | 10 | return true; | |
| 2217 | } | ||
| 2218 | } | ||
| 2219 | } | ||
| 2220 | |||
| 2221 | /* | ||
| 2222 | Keys disabled by ALTER TABLE ... DISABLE KEYS should have already | ||
| 2223 | been taken into account. | ||
| 2224 | */ | ||
| 2225 | 313782 | Key_map usable_keys = *map; | |
| 2226 | |||
| 2227 |
2/2✓ Branch 0 taken 325215 times.
✓ Branch 1 taken 52866 times.
|
378081 | for (ORDER *tmp_order = order.order; tmp_order; tmp_order = tmp_order->next) { |
| 2228 |
1/2✓ Branch 0 taken 325215 times.
✗ Branch 1 not taken.
|
325215 | const Item *item = (*tmp_order->item)->real_item(); |
| 2229 |
3/4✓ Branch 0 taken 325215 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13000 times.
✓ Branch 3 taken 312215 times.
|
325215 | if (item->type() != Item::FIELD_ITEM) { |
| 2230 | 13000 | usable_keys.clear_all(); | |
| 2231 | 13000 | return false; | |
| 2232 | } | ||
| 2233 | 312215 | usable_keys.intersect( | |
| 2234 | 312215 | down_cast<const Item_field *>(item)->field->part_of_sortkey); | |
| 2235 |
2/2✓ Branch 0 taken 247916 times.
✓ Branch 1 taken 64299 times.
|
312215 | if (usable_keys.is_clear_all()) return false; // No usable keys |
| 2236 | } | ||
| 2237 |
6/6✓ Branch 0 taken 52863 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 52828 times.
✓ Branch 4 taken 38 times.
✓ Branch 5 taken 52828 times.
|
52866 | if (tab->type() == JT_REF_OR_NULL || tab->type() == JT_FT) return false; |
| 2238 | |||
| 2239 | 52828 | ref_key = -1; | |
| 2240 | /* Test if constant range in WHERE */ | ||
| 2241 |
2/2✓ Branch 0 taken 1948 times.
✓ Branch 1 taken 50880 times.
|
52828 | if (tab->type() == JT_REF) { |
| 2242 |
2/4✓ Branch 0 taken 1948 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1948 times.
✗ Branch 3 not taken.
|
1948 | assert(tab->ref().key >= 0 && tab->ref().key_parts); |
| 2243 | 1948 | ref_key = tab->ref().key; | |
| 2244 | 1948 | ref_key_parts = tab->ref().key_parts; | |
| 2245 |
6/6✓ Branch 0 taken 44429 times.
✓ Branch 1 taken 6451 times.
✓ Branch 2 taken 52 times.
✓ Branch 3 taken 44377 times.
✓ Branch 4 taken 6503 times.
✓ Branch 5 taken 44377 times.
|
50880 | } else if (tab->type() == JT_RANGE || tab->type() == JT_INDEX_MERGE) { |
| 2246 | // Range found by opt_range | ||
| 2247 | /* | ||
| 2248 | assume results are not ordered when index merge is used | ||
| 2249 | TODO: sergeyp: Results of all index merge selects actually are ordered | ||
| 2250 | by clustered PK values. | ||
| 2251 | */ | ||
| 2252 | |||
| 2253 | 6503 | if (tab->range_scan()->type == AccessPath::INDEX_MERGE || | |
| 2254 |
6/6✓ Branch 0 taken 6467 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 6459 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 52 times.
✓ Branch 5 taken 6451 times.
|
12962 | tab->range_scan()->type == AccessPath::ROWID_UNION || |
| 2255 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6451 times.
|
6459 | tab->range_scan()->type == AccessPath::ROWID_INTERSECTION) |
| 2256 | 52 | return false; | |
| 2257 | 6451 | ref_key = used_index(tab->range_scan()); | |
| 2258 | 6451 | ref_key_parts = get_used_key_parts(tab->range_scan()); | |
| 2259 |
2/2✓ Branch 0 taken 4057 times.
✓ Branch 1 taken 40320 times.
|
44377 | } else if (tab->type() == JT_INDEX_SCAN) { |
| 2260 | // The optimizer has decided to use an index scan. | ||
| 2261 | 4057 | ref_key = tab->index(); | |
| 2262 |
1/2✓ Branch 0 taken 4057 times.
✗ Branch 1 not taken.
|
4057 | ref_key_parts = actual_key_parts(&table->key_info[tab->index()]); |
| 2263 | } | ||
| 2264 | |||
| 2265 | 52776 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 2266 |
1/2✓ Branch 0 taken 52776 times.
✗ Branch 1 not taken.
|
52776 | Opt_trace_object trace_wrapper_1(trace); |
| 2267 | Opt_trace_object trace_skip_sort_order( | ||
| 2268 |
1/2✓ Branch 0 taken 52776 times.
✗ Branch 1 not taken.
|
52776 | trace, "reconsidering_access_paths_for_index_ordering"); |
| 2269 |
1/2✓ Branch 0 taken 52776 times.
✗ Branch 1 not taken.
|
52776 | trace_skip_sort_order.add_alnum( |
| 2270 |
2/2✓ Branch 0 taken 49567 times.
✓ Branch 1 taken 3209 times.
|
52776 | "clause", (order.src == ESC_ORDER_BY ? "ORDER BY" : "GROUP BY")); |
| 2271 |
1/2✓ Branch 0 taken 52776 times.
✗ Branch 1 not taken.
|
52776 | Opt_trace_array trace_steps(trace, "steps"); |
| 2272 | |||
| 2273 |
2/2✓ Branch 0 taken 12456 times.
✓ Branch 1 taken 40320 times.
|
52776 | if (ref_key >= 0) { |
| 2274 | /* | ||
| 2275 | We come here when ref/index scan/range scan access has been set | ||
| 2276 | up for this table. Do not change access method if ordering is | ||
| 2277 | provided already. | ||
| 2278 | */ | ||
| 2279 |
2/2✓ Branch 0 taken 1183 times.
✓ Branch 1 taken 11273 times.
|
12456 | if (!usable_keys.is_set(ref_key)) { |
| 2280 | /* | ||
| 2281 | We come here when ref_key is not among usable_keys, try to find a | ||
| 2282 | usable prefix key of that key. | ||
| 2283 | */ | ||
| 2284 | uint new_ref_key; | ||
| 2285 | /* | ||
| 2286 | If using index only read, only consider other possible index only | ||
| 2287 | keys | ||
| 2288 | */ | ||
| 2289 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1182 times.
|
1183 | if (table->covering_keys.is_set(ref_key)) |
| 2290 | 1 | usable_keys.intersect(table->covering_keys); | |
| 2291 | |||
| 2292 |
1/2✓ Branch 0 taken 1183 times.
✗ Branch 1 not taken.
|
1183 | if ((new_ref_key = test_if_subkey(&order, tab, ref_key, ref_key_parts, |
| 2293 |
2/2✓ Branch 0 taken 347 times.
✓ Branch 1 taken 836 times.
|
1183 | &usable_keys)) < MAX_KEY) { |
| 2294 | /* Found key that can be used to retrieve data in sorted order */ | ||
| 2295 |
2/2✓ Branch 0 taken 331 times.
✓ Branch 1 taken 16 times.
|
347 | if (tab->ref().key >= 0) { |
| 2296 | /* | ||
| 2297 | We'll use ref access method on key new_ref_key. The actual change | ||
| 2298 | is done further down in this function where we update the plan. | ||
| 2299 | */ | ||
| 2300 | 331 | set_up_ref_access_to_key = true; | |
| 2301 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
|
16 | } else if (!no_changes) { |
| 2302 | /* | ||
| 2303 | The range optimizer constructed QUICK_RANGE for ref_key, and | ||
| 2304 | we want to use instead new_ref_key as the index. We can't | ||
| 2305 | just change the index of the quick select, because this may | ||
| 2306 | result in an inconsistent RowIterator object. Below we | ||
| 2307 | create a new RowIterator from scratch so that all its | ||
| 2308 | parameres are set correctly by the range optimizer. | ||
| 2309 | |||
| 2310 | Note that the range optimizer is NOT called if | ||
| 2311 | no_changes==true. This reason is that the range optimizer | ||
| 2312 | cannot find a QUICK that can return ordered result unless | ||
| 2313 | index access (ref or index scan) is also able to do so | ||
| 2314 | (which test_if_order_by_key () will tell). | ||
| 2315 | Admittedly, range access may be much more efficient than | ||
| 2316 | e.g. index scan, but the only thing that matters when | ||
| 2317 | no_change==true is the answer to the question: "Is it | ||
| 2318 | possible to avoid sorting if an index is used to access | ||
| 2319 | this table?". The answer does not depend on the outcome of | ||
| 2320 | the range optimizer. | ||
| 2321 | */ | ||
| 2322 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | Key_map new_ref_key_map; // Force the creation of quick select |
| 2323 | 14 | new_ref_key_map.set_bit(new_ref_key); // only for new_ref_key. | |
| 2324 | |||
| 2325 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | Opt_trace_object trace_wrapper_2(trace); |
| 2326 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | Opt_trace_object trace_recest(trace, "rows_estimation"); |
| 2327 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | trace_recest.add_utf8_table(tab->table_ref) |
| 2328 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | .add_utf8("index", table->key_info[new_ref_key].name); |
| 2329 | AccessPath *range_scan; | ||
| 2330 | MEM_ROOT temp_mem_root(key_memory_test_quick_select_exec, | ||
| 2331 | 14 | thd->variables.range_alloc_block_size); | |
| 2332 | const bool no_quick = | ||
| 2333 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
28 | test_quick_select( |
| 2334 | thd, thd->mem_root, &temp_mem_root, new_ref_key_map, 0, | ||
| 2335 | 0, // empty table_map | ||
| 2336 | 14 | join->calc_found_rows | |
| 2337 | ? HA_POS_ERROR | ||
| 2338 | 14 | : join->query_expression()->select_limit_cnt, | |
| 2339 | false, // don't force quick range | ||
| 2340 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | order.order->direction, tab->table(), |
| 2341 | 14 | tab->skip_records_in_range(), | |
| 2342 | // we are after make_join_query_block(): | ||
| 2343 | 14 | tab->condition(), &tab->needed_reg, tab->table()->force_index, | |
| 2344 | 14 | join->query_block, &range_scan) <= 0; | |
| 2345 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | assert(tab->range_scan() == save_range_scan); |
| 2346 | 14 | tab->set_range_scan(range_scan); | |
| 2347 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 11 times.
|
14 | if (no_quick) { |
| 2348 | 3 | can_skip_sorting = false; | |
| 2349 | 3 | goto fix_ICP; | |
| 2350 | } | ||
| 2351 |
6/6✓ Branch 0 taken 11 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 3 times.
|
20 | } |
| 2352 | 344 | ref_key = new_ref_key; | |
| 2353 | 344 | changed_key = new_ref_key; | |
| 2354 | } | ||
| 2355 | } | ||
| 2356 | bool dummy; | ||
| 2357 | /* Check if we get the rows in requested sorted order by using the key */ | ||
| 2358 |
2/2✓ Branch 0 taken 11617 times.
✓ Branch 1 taken 836 times.
|
12453 | if (usable_keys.is_set(ref_key)) |
| 2359 | // Last parameter can be ignored as it'll be checked later, if needed | ||
| 2360 | order_direction = | ||
| 2361 |
1/2✓ Branch 0 taken 11617 times.
✗ Branch 1 not taken.
|
11617 | test_if_order_by_key(&order, table, ref_key, &used_key_parts, &dummy); |
| 2362 | } | ||
| 2363 |
4/4✓ Branch 0 taken 12453 times.
✓ Branch 1 taken 40320 times.
✓ Branch 2 taken 5475 times.
✓ Branch 3 taken 6978 times.
|
52773 | if (ref_key < 0 || order_direction <= 0) { |
| 2364 | /* | ||
| 2365 | There is no ref/index scan/range scan access set up for this | ||
| 2366 | table, or it does not provide the requested ordering, or it uses | ||
| 2367 | backward scan. Do a cost-based search on all keys. | ||
| 2368 | */ | ||
| 2369 | 45795 | uint best_key_parts = 0; | |
| 2370 | 45795 | uint saved_best_key_parts = 0; | |
| 2371 | 45795 | int best_key_direction = 0; | |
| 2372 | 45795 | ha_rows table_records = table->file->stats.records; | |
| 2373 | |||
| 2374 | /* | ||
| 2375 | If an index scan that cannot provide ordering has been selected | ||
| 2376 | then do not use the index scan key as starting hint to | ||
| 2377 | test_if_cheaper_ordering() | ||
| 2378 | */ | ||
| 2379 | const int ref_key_hint = | ||
| 2380 |
4/4✓ Branch 0 taken 43736 times.
✓ Branch 1 taken 2059 times.
✓ Branch 2 taken 42588 times.
✓ Branch 3 taken 1148 times.
|
45795 | (order_direction == 0 && tab->type() == JT_INDEX_SCAN) ? -1 : ref_key; |
| 2381 | |||
| 2382 | // Does the query have a "FORCE INDEX [FOR GROUP BY] (idx)" (if clause is | ||
| 2383 | // group by) or a "FORCE INDEX [FOR ORDER BY] (idx)" (if clause is order | ||
| 2384 | // by)? | ||
| 2385 | 45795 | const bool is_group_by = | |
| 2386 |
4/6✓ Branch 0 taken 45795 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1047 times.
✓ Branch 3 taken 44748 times.
✓ Branch 4 taken 1047 times.
✗ Branch 5 not taken.
|
45795 | join && join->grouped && order.order == join->group_list.order; |
| 2387 | 45795 | const bool is_force_index = | |
| 2388 |
4/4✓ Branch 0 taken 45710 times.
✓ Branch 1 taken 85 times.
✓ Branch 2 taken 1031 times.
✓ Branch 3 taken 44679 times.
|
91505 | table->force_index || |
| 2389 |
4/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1029 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 44676 times.
|
45710 | (is_group_by ? table->force_index_group : table->force_index_order); |
| 2390 | |||
| 2391 | // Find an ordering index alternative over the chosen plan iff | ||
| 2392 | // prefer_ordering_index switch is on. This switch is overridden only when | ||
| 2393 | // force index for order/group is specified. | ||
| 2394 |
6/6✓ Branch 0 taken 10 times.
✓ Branch 1 taken 45785 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 45787 times.
✓ Branch 5 taken 8 times.
|
45795 | if (thd->optimizer_switch_flag(OPTIMIZER_SWITCH_PREFER_ORDERING_INDEX) || |
| 2395 | is_force_index) | ||
| 2396 |
1/2✓ Branch 0 taken 45787 times.
✗ Branch 1 not taken.
|
45787 | test_if_cheaper_ordering(tab, &order, table, usable_keys, ref_key_hint, |
| 2397 | select_limit, &best_key, &best_key_direction, | ||
| 2398 | &select_limit, &best_key_parts, | ||
| 2399 | &saved_best_key_parts); | ||
| 2400 | |||
| 2401 | // Try backward scan for previously found key | ||
| 2402 |
4/4✓ Branch 0 taken 33320 times.
✓ Branch 1 taken 12475 times.
✓ Branch 2 taken 2037 times.
✓ Branch 3 taken 31283 times.
|
45805 | if (best_key < 0 && order_direction < 0) goto check_reverse_order; |
| 2403 | |||
| 2404 |
2/2✓ Branch 0 taken 31283 times.
✓ Branch 1 taken 12475 times.
|
43758 | if (best_key < 0) { |
| 2405 | // No usable key has been found | ||
| 2406 | 31283 | can_skip_sorting = false; | |
| 2407 | 31305 | goto fix_ICP; | |
| 2408 | } | ||
| 2409 | /* | ||
| 2410 | If found index will use backward index scan, ref_key uses backward | ||
| 2411 | range/ref, pick the latter as it has better selectivity. | ||
| 2412 | */ | ||
| 2413 |
4/4✓ Branch 0 taken 22 times.
✓ Branch 1 taken 12453 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 12 times.
|
12475 | if (order_direction < 0 && order_direction == best_key_direction) { |
| 2414 | 10 | best_key = -1; // reset found best key | |
| 2415 | 10 | goto check_reverse_order; | |
| 2416 | } | ||
| 2417 | |||
| 2418 | /* | ||
| 2419 | filesort() and join cache are usually faster than reading in | ||
| 2420 | index order and not using join cache. Don't use index scan | ||
| 2421 | unless: | ||
| 2422 | - the user specified FORCE INDEX [FOR {GROUP|ORDER} BY] (have to assume | ||
| 2423 | the user knows what's best) | ||
| 2424 | - the chosen index is clustered primary key (table scan is not cheaper) | ||
| 2425 | */ | ||
| 2426 |
4/4✓ Branch 0 taken 9344 times.
✓ Branch 1 taken 3049 times.
✓ Branch 2 taken 8053 times.
✓ Branch 3 taken 1291 times.
|
21737 | if (!is_force_index && (select_limit >= table_records) && |
| 2427 | 9344 | (tab->type() == JT_ALL && | |
| 2428 |
6/6✓ Branch 0 taken 12393 times.
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 78 times.
✓ Branch 3 taken 7975 times.
✓ Branch 4 taken 22 times.
✓ Branch 5 taken 12443 times.
|
24936 | join->primary_tables > join->const_tables + 1) && |
| 2429 |
2/2✓ Branch 0 taken 59 times.
✓ Branch 1 taken 19 times.
|
78 | ((unsigned)best_key != table->s->primary_key || |
| 2430 |
3/4✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 56 times.
|
59 | !table->file->primary_key_is_clustered())) { |
| 2431 | 22 | can_skip_sorting = false; | |
| 2432 | 22 | goto fix_ICP; | |
| 2433 | } | ||
| 2434 | |||
| 2435 | 12443 | if (table->quick_keys.is_set(best_key) && | |
| 2436 |
6/8✓ Branch 0 taken 103 times.
✓ Branch 1 taken 12340 times.
✓ Branch 2 taken 103 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 103 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 103 times.
✓ Branch 7 taken 12340 times.
|
12443 | !tab->quick_order_tested.is_set(best_key) && best_key != ref_key) { |
| 2437 | 103 | tab->quick_order_tested.set_bit(best_key); | |
| 2438 |
1/2✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
|
103 | Opt_trace_object trace_wrapper_3(trace); |
| 2439 |
1/2✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
|
103 | Opt_trace_object trace_recest(trace, "rows_estimation"); |
| 2440 |
1/2✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
|
103 | trace_recest.add_utf8_table(tab->table_ref) |
| 2441 |
1/2✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
|
103 | .add_utf8("index", table->key_info[best_key].name); |
| 2442 | |||
| 2443 |
1/2✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
|
103 | Key_map keys_to_use; // Force the creation of quick select |
| 2444 | 103 | keys_to_use.set_bit(best_key); // only best_key. | |
| 2445 | MEM_ROOT temp_mem_root(key_memory_test_quick_select_exec, | ||
| 2446 | 103 | thd->variables.range_alloc_block_size); | |
| 2447 | AccessPath *range_scan; | ||
| 2448 |
1/2✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
|
206 | test_quick_select( |
| 2449 | thd, thd->mem_root, &temp_mem_root, keys_to_use, 0, | ||
| 2450 | 0, // empty table_map | ||
| 2451 | 103 | join->calc_found_rows ? HA_POS_ERROR | |
| 2452 | 103 | : join->query_expression()->select_limit_cnt, | |
| 2453 | true, // force quick range | ||
| 2454 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 103 times.
|
206 | order.order->direction, tab->table(), tab->skip_records_in_range(), |
| 2455 | 103 | tab->condition(), &tab->needed_reg, tab->table()->force_index, | |
| 2456 | 103 | join->query_block, &range_scan); | |
| 2457 |
6/8✓ Branch 0 taken 2 times.
✓ Branch 1 taken 101 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 101 times.
|
105 | if (order_direction < 0 && tab->range_scan() != nullptr && |
| 2458 | 2 | tab->range_scan() != save_range_scan) { | |
| 2459 | /* | ||
| 2460 | We came here in case when 3 indexes are available for quick | ||
| 2461 | select: | ||
| 2462 | 1 - found by join order optimizer (greedy search) and saved in | ||
| 2463 | save_range_scan | ||
| 2464 | 2 - constructed far above, as better suited for order by, but it was | ||
| 2465 | found that it requires backward scan. | ||
| 2466 | 3 - constructed right above | ||
| 2467 | In this case we drop quick #2 as #3 is expected to be better. | ||
| 2468 | */ | ||
| 2469 | 2 | destroy(tab->range_scan()); | |
| 2470 | 2 | tab->set_range_scan(nullptr); | |
| 2471 | } | ||
| 2472 | /* | ||
| 2473 | If tab->range_scan() pointed to another quick than save_range_scan, we | ||
| 2474 | would lose access to it and leak memory. | ||
| 2475 | */ | ||
| 2476 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 101 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
103 | assert(tab->range_scan() == save_range_scan || |
| 2477 | tab->range_scan() == nullptr); | ||
| 2478 | 103 | tab->set_range_scan(range_scan); | |
| 2479 |
6/6✓ Branch 0 taken 79 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 78 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 78 times.
✓ Branch 5 taken 25 times.
|
103 | if (tab->range_scan() && !no_changes) |
| 2480 |
1/2✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
|
78 | tab->set_type(calc_join_type(tab->range_scan())); |
| 2481 | 103 | } | |
| 2482 | 12443 | order_direction = best_key_direction; | |
| 2483 | /* | ||
| 2484 | saved_best_key_parts is actual number of used keyparts found by the | ||
| 2485 | test_if_order_by_key function. It could differ from keyinfo->key_parts, | ||
| 2486 | thus we have to restore it in case of desc order as it affects | ||
| 2487 | ReverseIndexRangeScanIterator behaviour. | ||
| 2488 | */ | ||
| 2489 | 12443 | used_key_parts = | |
| 2490 |
2/2✓ Branch 0 taken 1225 times.
✓ Branch 1 taken 11218 times.
|
12443 | (order_direction == -1) ? saved_best_key_parts : best_key_parts; |
| 2491 | 12443 | changed_key = best_key; | |
| 2492 | // We will use index scan or range scan: | ||
| 2493 | 12443 | set_up_ref_access_to_key = false; | |
| 2494 | } | ||
| 2495 | |||
| 2496 | 6978 | check_reverse_order: | |
| 2497 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21468 times.
|
21468 | assert(order_direction != 0); |
| 2498 | |||
| 2499 |
2/2✓ Branch 0 taken 3272 times.
✓ Branch 1 taken 18196 times.
|
21468 | if (order_direction == -1) // If ORDER BY ... DESC |
| 2500 | { | ||
| 2501 |
2/2✓ Branch 0 taken 1259 times.
✓ Branch 1 taken 2013 times.
|
3272 | if (tab->range_scan()) { |
| 2502 | /* | ||
| 2503 | Don't reverse the sort order, if it's already done. | ||
| 2504 | (In some cases test_if_order_by_key() can be called multiple times | ||
| 2505 | */ | ||
| 2506 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1259 times.
|
1259 | if (is_reverse_sorted_range(tab->range_scan())) { |
| 2507 | ✗ | can_skip_sorting = true; | |
| 2508 | ✗ | goto fix_ICP; | |
| 2509 | } | ||
| 2510 | // test_if_cheaper_ordering() might disable range scan on current index | ||
| 2511 |
5/6✓ Branch 0 taken 1253 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1253 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1253 times.
✓ Branch 5 taken 6 times.
|
2512 | if (tab->table()->quick_keys.is_set(used_index(tab->range_scan())) && |
| 2512 | 1253 | reverse_sort_possible(tab->range_scan())) | |
| 2513 | 1253 | can_skip_sorting = true; | |
| 2514 | else { | ||
| 2515 | 6 | can_skip_sorting = false; | |
| 2516 | 6 | goto fix_ICP; | |
| 2517 | } | ||
| 2518 | } else { | ||
| 2519 | // Other index access (ref or scan) poses no problem | ||
| 2520 | 2013 | can_skip_sorting = true; | |
| 2521 | } | ||
| 2522 | } else { | ||
| 2523 | // ORDER BY ASC poses no problem | ||
| 2524 | 18196 | can_skip_sorting = true; | |
| 2525 | } | ||
| 2526 | |||
| 2527 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21462 times.
|
21462 | assert(can_skip_sorting); |
| 2528 | |||
| 2529 | /* | ||
| 2530 | Update query plan with access pattern for doing | ||
| 2531 | ordered access according to what we have decided | ||
| 2532 | above. | ||
| 2533 | */ | ||
| 2534 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 21408 times.
|
21462 | if (!no_changes) // We are allowed to update QEP |
| 2535 | { | ||
| 2536 |
2/2✓ Branch 0 taken 319 times.
✓ Branch 1 taken 21089 times.
|
21408 | if (set_up_ref_access_to_key) { |
| 2537 | /* | ||
| 2538 | We'll use ref access method on key changed_key. In general case | ||
| 2539 | the index search tuple for changed_ref_key will be different (e.g. | ||
| 2540 | when one index is defined as (part1, part2, ...) and another as | ||
| 2541 | (part1, part2(N), ...) and the WHERE clause contains | ||
| 2542 | "part1 = const1 AND part2=const2". | ||
| 2543 | So we build tab->ref() from scratch here. | ||
| 2544 | */ | ||
| 2545 | 319 | Key_use *keyuse = tab->keyuse(); | |
| 2546 |
2/2✓ Branch 0 taken 303 times.
✓ Branch 1 taken 319 times.
|
622 | while (keyuse->key != (uint)changed_key && |
| 2547 |
1/2✓ Branch 0 taken 303 times.
✗ Branch 1 not taken.
|
303 | keyuse->table_ref == tab->table_ref) |
| 2548 | 303 | keyuse++; | |
| 2549 | |||
| 2550 |
2/4✓ Branch 0 taken 319 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 319 times.
|
319 | if (create_ref_for_key(join, tab, keyuse, tab->prefix_tables())) { |
| 2551 | ✗ | can_skip_sorting = false; | |
| 2552 | ✗ | goto fix_ICP; | |
| 2553 | } | ||
| 2554 | |||
| 2555 |
2/4✓ Branch 0 taken 319 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 319 times.
✗ Branch 3 not taken.
|
319 | assert(tab->type() != JT_REF_OR_NULL && tab->type() != JT_FT); |
| 2556 | |||
| 2557 | // Changing the key makes filter_effect obsolete | ||
| 2558 | 319 | tab->position()->filter_effect = COND_FILTER_STALE; | |
| 2559 | |||
| 2560 | /* | ||
| 2561 | Check if it is possible to shift from ref to range. The index chosen | ||
| 2562 | for 'ref' has changed since the last time this function was called. | ||
| 2563 | */ | ||
| 2564 |
3/4✓ Branch 0 taken 319 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 303 times.
|
319 | if (can_switch_from_ref_to_range(thd, tab, order.order->direction, |
| 2565 | true)) { | ||
| 2566 | // Allow the code to fall-through to the next if condition. | ||
| 2567 | 16 | set_up_ref_access_to_key = false; | |
| 2568 | 16 | best_key = changed_key; | |
| 2569 | } | ||
| 2570 | } | ||
| 2571 |
4/4✓ Branch 0 taken 21105 times.
✓ Branch 1 taken 303 times.
✓ Branch 2 taken 12449 times.
✓ Branch 3 taken 8656 times.
|
21408 | if (!set_up_ref_access_to_key && best_key >= 0) { |
| 2572 | // Cancel any ref-access previously set up | ||
| 2573 | 12449 | tab->ref().key = -1; | |
| 2574 | 12449 | tab->ref().key_parts = 0; | |
| 2575 | |||
| 2576 | /* | ||
| 2577 | If ref_key used index tree reading only ('Using index' in EXPLAIN), | ||
| 2578 | and best_key doesn't, then revert the decision. | ||
| 2579 | */ | ||
| 2580 |
3/4✓ Branch 0 taken 12373 times.
✓ Branch 1 taken 76 times.
✓ Branch 2 taken 12373 times.
✗ Branch 3 not taken.
|
12449 | if (!table->covering_keys.is_set(best_key)) table->set_keyread(false); |
| 2581 | // Create an index scan if the table is not a temporary table that uses | ||
| 2582 | // Temptable engine (Does not support index_first() and index_last()) and | ||
| 2583 | // if there was no new range scan created. | ||
| 2584 | 12449 | if (!(is_temporary_table(tab->table_ref) && | |
| 2585 |
8/10✓ Branch 0 taken 79 times.
✓ Branch 1 taken 12370 times.
✓ Branch 2 taken 79 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 79 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 639 times.
✓ Branch 7 taken 11810 times.
✓ Branch 8 taken 12355 times.
✓ Branch 9 taken 94 times.
|
25537 | tab->table_ref->table->s->db_type() == temptable_hton) && |
| 2586 |
2/2✓ Branch 0 taken 545 times.
✓ Branch 1 taken 94 times.
|
13088 | ((!tab->range_scan() || tab->range_scan() == save_range_scan))) { |
| 2587 | // Avoid memory leak: | ||
| 2588 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 12355 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
12355 | assert(tab->range_scan() == save_range_scan || |
| 2589 | tab->range_scan() == nullptr); | ||
| 2590 | 12355 | tab->set_range_scan(nullptr); | |
| 2591 | 12355 | tab->set_index(best_key); | |
| 2592 | 12355 | tab->set_type(JT_INDEX_SCAN); // Read with index_first(), index_next() | |
| 2593 | /* | ||
| 2594 | There is a bug. When we change here, e.g. from group_min_max to | ||
| 2595 | index scan: loose index scan expected to read a small number of rows | ||
| 2596 | (jumping through the index), this small number was in | ||
| 2597 | position()->rows_fetched; index scan will read much more, so | ||
| 2598 | rows_fetched should be updated. So should the filtering effect. | ||
| 2599 | It is visible in main.distinct in trunk: | ||
| 2600 | explain SELECT distinct a from t3 order by a desc limit 2; | ||
| 2601 | id select_type table partitions type | ||
| 2602 | possible_keys key key_len ref rows filtered Extra 1 | ||
| 2603 | SIMPLE t3 NULL index a a 5 NULL | ||
| 2604 | 40 25.00 Using index "rows=40" should be ~200 i.e. # of records | ||
| 2605 | in table. Filter should be 100.00 (no WHERE). | ||
| 2606 | */ | ||
| 2607 |
1/2✓ Branch 0 taken 12355 times.
✗ Branch 1 not taken.
|
12355 | table->file->ha_index_or_rnd_end(); |
| 2608 | 12355 | tab->position()->filter_effect = COND_FILTER_STALE; | |
| 2609 |
1/2✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
|
94 | } else if (tab->type() != JT_ALL) { |
| 2610 | /* | ||
| 2611 | We're about to use a quick access to the table. | ||
| 2612 | We need to change the access method so as the quick access | ||
| 2613 | method is actually used. | ||
| 2614 | */ | ||
| 2615 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
|
94 | assert(tab->range_scan()); |
| 2616 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
|
94 | assert(used_index(tab->range_scan()) == (uint)best_key); |
| 2617 |
1/2✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
|
94 | tab->set_type(calc_join_type(tab->range_scan())); |
| 2618 | 94 | tab->use_quick = QS_RANGE; | |
| 2619 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
|
94 | if (is_loose_index_scan(tab->range_scan())) |
| 2620 | ✗ | join->tmp_table_param.precomputed_group_by = true; | |
| 2621 | 94 | tab->position()->filter_effect = COND_FILTER_STALE; | |
| 2622 | } | ||
| 2623 | } // best_key >= 0 | ||
| 2624 | |||
| 2625 |
2/2✓ Branch 0 taken 3244 times.
✓ Branch 1 taken 18164 times.
|
21408 | if (order_direction == -1) // If ORDER BY ... DESC |
| 2626 | { | ||
| 2627 |
2/2✓ Branch 0 taken 1219 times.
✓ Branch 1 taken 2025 times.
|
3244 | if (tab->range_scan()) { |
| 2628 | /* ORDER BY range_key DESC */ | ||
| 2629 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1219 times.
|
1219 | if (make_reverse(used_key_parts, tab->range_scan())) { |
| 2630 | /* purecov: begin inspected */ | ||
| 2631 | ✗ | can_skip_sorting = false; // Reverse sort failed -> filesort | |
| 2632 | ✗ | goto fix_ICP; | |
| 2633 | /* purecov: end */ | ||
| 2634 | } | ||
| 2635 |
1/2✓ Branch 0 taken 1219 times.
✗ Branch 1 not taken.
|
1219 | tab->set_type(calc_join_type(tab->range_scan())); |
| 2636 | 1219 | tab->position()->filter_effect = COND_FILTER_STALE; | |
| 2637 |
4/4✓ Branch 0 taken 504 times.
✓ Branch 1 taken 1521 times.
✓ Branch 2 taken 504 times.
✓ Branch 3 taken 1521 times.
|
2529 | } else if (tab->type() == JT_REF && |
| 2638 |
1/2✓ Branch 0 taken 504 times.
✗ Branch 1 not taken.
|
504 | tab->ref().key_parts <= used_key_parts) { |
| 2639 | /* | ||
| 2640 | SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC | ||
| 2641 | |||
| 2642 | Use a traversal function that starts by reading the last row | ||
| 2643 | with key part (A) and then traverse the index backwards. | ||
| 2644 | */ | ||
| 2645 | 504 | tab->reversed_access = true; | |
| 2646 | |||
| 2647 | /* | ||
| 2648 | The current implementation of the reverse RefIterator does not | ||
| 2649 | work well in combination with ICP and can lead to increased | ||
| 2650 | execution time. Setting changed_key to the current key | ||
| 2651 | (based on that we change the access order for the key) will | ||
| 2652 | ensure that a pushed index condition will be cancelled. | ||
| 2653 | */ | ||
| 2654 | 504 | changed_key = tab->ref().key; | |
| 2655 |
1/2✓ Branch 0 taken 1521 times.
✗ Branch 1 not taken.
|
1521 | } else if (tab->type() == JT_INDEX_SCAN) |
| 2656 | 1521 | tab->reversed_access = true; | |
| 2657 |
2/2✓ Branch 0 taken 3602 times.
✓ Branch 1 taken 14562 times.
|
18164 | } else if (tab->range_scan()) |
| 2658 | 3602 | set_need_sorted_output(tab->range_scan()); | |
| 2659 | |||
| 2660 | } // QEP has been modified | ||
| 2661 | |||
| 2662 | 54 | fix_ICP: | |
| 2663 | /* | ||
| 2664 | Cleanup: | ||
| 2665 | We may have both a 'tab->range_scan()' and 'save_range_scan' (original) | ||
| 2666 | at this point. Delete the one that we won't use. | ||
| 2667 | */ | ||
| 2668 |
4/4✓ Branch 0 taken 21462 times.
✓ Branch 1 taken 31314 times.
✓ Branch 2 taken 21408 times.
✓ Branch 3 taken 54 times.
|
52776 | if (can_skip_sorting && !no_changes) { |
| 2669 |
4/4✓ Branch 0 taken 15223 times.
✓ Branch 1 taken 6185 times.
✓ Branch 2 taken 3145 times.
✓ Branch 3 taken 18263 times.
|
36631 | if (tab->type() == JT_INDEX_SCAN && |
| 2670 |
2/2✓ Branch 0 taken 3145 times.
✓ Branch 1 taken 12078 times.
|
15223 | select_limit < table->file->stats.records) { |
| 2671 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3145 times.
|
3145 | assert(select_limit > 0); |
| 2672 | 3145 | tab->position()->rows_fetched = select_limit; | |
| 2673 | 3145 | tab->position()->filter_effect = COND_FILTER_STALE_NO_CONST; | |
| 2674 | } | ||
| 2675 | |||
| 2676 | // Keep current (ordered) tab->range_scan() | ||
| 2677 |
2/2✓ Branch 0 taken 648 times.
✓ Branch 1 taken 20760 times.
|
21408 | if (save_range_scan != tab->range_scan()) destroy(save_range_scan); |
| 2678 | } else { | ||
| 2679 | // Restore original save_range_scan | ||
| 2680 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 31364 times.
|
31368 | if (tab->range_scan() != save_range_scan) { |
| 2681 | 4 | destroy(tab->range_scan()); | |
| 2682 | 4 | tab->set_range_scan(save_range_scan); | |
| 2683 | } | ||
| 2684 | } | ||
| 2685 | |||
| 2686 |
1/2✓ Branch 0 taken 52776 times.
✗ Branch 1 not taken.
|
52776 | trace_steps.end(); |
| 2687 |
1/2✓ Branch 0 taken 52776 times.
✗ Branch 1 not taken.
|
52776 | Opt_trace_object trace_change_index(trace, "index_order_summary"); |
| 2688 |
1/2✓ Branch 0 taken 52776 times.
✗ Branch 1 not taken.
|
52776 | trace_change_index.add_utf8_table(tab->table_ref) |
| 2689 |
1/2✓ Branch 0 taken 52776 times.
✗ Branch 1 not taken.
|
52776 | .add("index_provides_order", can_skip_sorting) |
| 2690 |
3/4✓ Branch 0 taken 34580 times.
✓ Branch 1 taken 18196 times.
✓ Branch 2 taken 52776 times.
✗ Branch 3 not taken.
|
87356 | .add_alnum("order_direction", |
| 2691 | order_direction == 1 | ||
| 2692 | ? "asc" | ||
| 2693 |
2/2✓ Branch 0 taken 3272 times.
✓ Branch 1 taken 31308 times.
|
34580 | : ((order_direction == -1) ? "desc" : "undefined")); |
| 2694 | |||
| 2695 |
2/2✓ Branch 0 taken 13289 times.
✓ Branch 1 taken 39487 times.
|
52776 | if (changed_key >= 0) { |
| 2696 | // switching to another index | ||
| 2697 | // Should be no pushed index conditions at this point | ||
| 2698 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13289 times.
|
13289 | assert(!table->file->pushed_idx_cond); |
| 2699 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 13249 times.
|
13289 | if (unlikely(trace->is_started())) { |
| 2700 |
1/2✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
|
40 | trace_change_index.add_utf8("index", table->key_info[changed_key].name); |
| 2701 |
1/2✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
|
40 | trace_change_index.add("plan_changed", !no_changes); |
| 2702 |
1/2✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
|
40 | if (!no_changes) |
| 2703 |
1/2✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
|
40 | trace_change_index.add_alnum("access_type", join_type_str[tab->type()]); |
| 2704 | } | ||
| 2705 |
2/2✓ Branch 0 taken 81 times.
✓ Branch 1 taken 39406 times.
|
39487 | } else if (unlikely(trace->is_started())) { |
| 2706 |
2/4✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
|
162 | trace_change_index.add_utf8( |
| 2707 | 81 | "index", ref_key >= 0 ? table->key_info[ref_key].name : "unknown"); | |
| 2708 |
1/2✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
|
81 | trace_change_index.add("plan_changed", false); |
| 2709 | } | ||
| 2710 |
2/2✓ Branch 0 taken 40295 times.
✓ Branch 1 taken 12481 times.
|
52776 | *order_idx = best_key < 0 ? ref_key : best_key; |
| 2711 | 52776 | return can_skip_sorting; | |
| 2712 | 313823 | } | |
| 2713 | |||
| 2714 | /** | ||
| 2715 | Prune partitions for all tables of a join (query block). | ||
| 2716 | |||
| 2717 | Requires that tables have been locked. | ||
| 2718 | |||
| 2719 | @returns false if success, true if error | ||
| 2720 | */ | ||
| 2721 | |||
| 2722 | 83698 | bool JOIN::prune_table_partitions() { | |
| 2723 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 83698 times.
|
83698 | assert(query_block->partitioned_table_count); |
| 2724 | |||
| 2725 |
2/2✓ Branch 0 taken 84079 times.
✓ Branch 1 taken 83695 times.
|
167774 | for (TABLE_LIST *tbl = query_block->leaf_tables; tbl; tbl = tbl->next_leaf) { |
| 2726 | // This will try to prune non-static conditions, which can be probed after | ||
| 2727 | // the tables are locked. | ||
| 2728 | |||
| 2729 | // Predicates for pruning of this table must be placed in the outer-most | ||
| 2730 | // join nest (Predicates in other join nests, or in the WHERE clause, | ||
| 2731 | // would have caused an outer join to be converted to an inner join, | ||
| 2732 | // and thus there would be no join nest graph to traverse) | ||
| 2733 | // Look up the join nest hierarchy for the outermost condition: | ||
| 2734 | 84079 | Item *cond = where_cond; | |
| 2735 | 84079 | const table_map tbl_map = tbl->map(); | |
| 2736 |
2/2✓ Branch 0 taken 84089 times.
✓ Branch 1 taken 84079 times.
|
168168 | for (TABLE_LIST *nest = tbl; nest != nullptr; nest = nest->embedding) { |
| 2737 |
6/6✓ Branch 0 taken 12 times.
✓ Branch 1 taken 84077 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 84080 times.
|
84101 | if (nest->join_cond_optim() != nullptr && |
| 2738 | 12 | Overlaps(tbl_map, nest->join_cond_optim()->used_tables())) { | |
| 2739 | 9 | cond = nest->join_cond_optim(); | |
| 2740 | // For an anti-join operation, a synthetic left join nest is added above | ||
| 2741 | // the anti-join nest. Make sure that we skip this when searching for | ||
| 2742 | // the predicate to prune. | ||
| 2743 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | if (nest->is_aj_nest()) break; |
| 2744 | } | ||
| 2745 | } | ||
| 2746 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 84076 times.
|
84079 | if (prune_partitions(thd, tbl->table, query_block, cond)) { |
| 2747 | 3 | return true; | |
| 2748 | } | ||
| 2749 | } | ||
| 2750 | |||
| 2751 | 83695 | return false; | |
| 2752 | } | ||
| 2753 | |||
| 2754 | /** | ||
| 2755 | A helper function to check whether it's better to use range than ref. | ||
| 2756 | |||
| 2757 | @details | ||
| 2758 | Heuristic: Switch from 'ref' to 'range' access if 'range' | ||
| 2759 | access can utilize more keyparts than 'ref' access. Conditions | ||
| 2760 | for doing switching: | ||
| 2761 | |||
| 2762 | 1) Range access is possible | ||
| 2763 | 2) 'ref' access and 'range' access uses the same index | ||
| 2764 | 3) Used parts of key shouldn't have nullable parts & ref_or_null isn't used. | ||
| 2765 | 4) 'ref' access depends on a constant, not a value read from a | ||
| 2766 | table earlier in the join sequence. | ||
| 2767 | |||
| 2768 | Rationale: if 'ref' depends on a value from another table, | ||
| 2769 | the join condition is not used to limit the rows read by | ||
| 2770 | 'range' access (that would require dynamic range - 'Range | ||
| 2771 | checked for each record'). In other words, if 'ref' depends | ||
| 2772 | on a value from another table, we have a query with | ||
| 2773 | conditions of the form | ||
| 2774 | |||
| 2775 | this_table.idx_col1 = other_table.col AND <<- used by 'ref' | ||
| 2776 | this_table.idx_col1 OP @<const@> AND <<- used by 'range' | ||
| 2777 | this_table.idx_col2 OP @<const@> AND ... <<- used by 'range' | ||
| 2778 | |||
| 2779 | and an index on (idx_col1,idx_col2,...). But the fact that | ||
| 2780 | 'range' access uses more keyparts does not mean that it is | ||
| 2781 | more selective than 'ref' access because these access types | ||
| 2782 | utilize different parts of the query condition. We | ||
| 2783 | therefore trust the cost based choice made by | ||
| 2784 | best_access_path() instead of forcing a heuristic choice | ||
| 2785 | here. | ||
| 2786 | 5) 'range' access uses more keyparts than 'ref' access | ||
| 2787 | 6) ORDER BY might make range better than table scan: | ||
| 2788 | Check possibility of range scan even if it was previously deemed unviable | ||
| 2789 | (for example when table scan was estimated to be cheaper). If yes, | ||
| 2790 | range-access should be chosen only for larger key length. | ||
| 2791 | |||
| 2792 | @param thd To re-run range optimizer. | ||
| 2793 | @param tab JOIN_TAB to check | ||
| 2794 | @param ordering Used as a parameter to call test_quick_select. | ||
| 2795 | @param recheck_range Check possibility of range scan even if it is currently | ||
| 2796 | unviable. | ||
| 2797 | |||
| 2798 | @return true Range is better than ref | ||
| 2799 | @return false Ref is better or switch isn't possible | ||
| 2800 | |||
| 2801 | @todo: This decision should rather be made in best_access_path() | ||
| 2802 | */ | ||
| 2803 | |||
| 2804 | 1940234 | static bool can_switch_from_ref_to_range(THD *thd, JOIN_TAB *tab, | |
| 2805 | enum_order ordering, | ||
| 2806 | bool recheck_range) { | ||
| 2807 |
2/2✓ Branch 0 taken 4913 times.
✓ Branch 1 taken 95668 times.
|
2040815 | if ((tab->range_scan() && // 1) |
| 2808 |
6/6✓ Branch 0 taken 100574 times.
✓ Branch 1 taken 1839724 times.
✓ Branch 2 taken 319 times.
✓ Branch 3 taken 1844318 times.
✓ Branch 4 taken 95987 times.
✓ Branch 5 taken 1844318 times.
|
2040879 | tab->position()->key->key == used_index(tab->range_scan())) || // 2) |
| 2809 | recheck_range) { | ||
| 2810 | 95987 | uint keyparts = 0, length = 0; | |
| 2811 | 95987 | table_map dep_map = 0; | |
| 2812 | 95987 | bool maybe_null = false; | |
| 2813 | |||
| 2814 |
1/2✓ Branch 0 taken 95987 times.
✗ Branch 1 not taken.
|
191974 | calc_length_and_keyparts(tab->position()->key, tab, |
| 2815 | 95987 | tab->position()->key->key, tab->prefix_tables(), | |
| 2816 | nullptr, &length, &keyparts, &dep_map, | ||
| 2817 | &maybe_null); | ||
| 2818 |
2/2✓ Branch 0 taken 95847 times.
✓ Branch 1 taken 140 times.
|
95987 | if (!maybe_null && // 3) |
| 2819 |
2/2✓ Branch 0 taken 74072 times.
✓ Branch 1 taken 21775 times.
|
95847 | !dep_map) // 4) |
| 2820 | { | ||
| 2821 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 74043 times.
|
74072 | if (recheck_range) // 6) |
| 2822 | { | ||
| 2823 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | Key_map new_ref_key_map; |
| 2824 | 29 | new_ref_key_map.set_bit(tab->ref().key); | |
| 2825 | |||
| 2826 | 29 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 2827 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | Opt_trace_object trace_wrapper(trace); |
| 2828 | Opt_trace_object can_switch( | ||
| 2829 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | trace, "check_if_range_uses_more_keyparts_than_ref"); |
| 2830 | Opt_trace_object trace_cond( | ||
| 2831 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | trace, "rerunning_range_optimizer_for_single_index"); |
| 2832 | |||
| 2833 | AccessPath *range_scan; | ||
| 2834 | MEM_ROOT temp_mem_root(key_memory_test_quick_select_exec, | ||
| 2835 | 29 | thd->variables.range_alloc_block_size); | |
| 2836 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
|
116 | if (test_quick_select( |
| 2837 | thd, thd->mem_root, &temp_mem_root, new_ref_key_map, 0, | ||
| 2838 | 0, // empty table_map | ||
| 2839 | 29 | tab->join()->row_limit, false, ordering, tab->table(), | |
| 2840 | 29 | tab->skip_records_in_range(), | |
| 2841 | 29 | tab->join_cond() ? tab->join_cond() : tab->join()->where_cond, | |
| 2842 | 29 | &tab->needed_reg, recheck_range, tab->join()->query_block, | |
| 2843 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 6 times.
|
29 | &range_scan) > 0) { |
| 2844 |
3/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 7 times.
|
23 | if (length < get_max_used_key_length(range_scan)) { |
| 2845 | 16 | destroy(tab->range_scan()); | |
| 2846 | 16 | tab->set_range_scan(range_scan); | |
| 2847 | 16 | return true; | |
| 2848 | } | ||
| 2849 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
14 | Opt_trace_object(trace, "access_type_unchanged") |
| 2850 | 14 | .add("ref_key_length", length) | |
| 2851 |
3/6✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
7 | .add("range_key_length", get_max_used_key_length(range_scan)); |
| 2852 | 7 | destroy(range_scan); | |
| 2853 | } | ||
| 2854 |
8/8✓ Branch 0 taken 13 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 16 times.
✓ Branch 6 taken 13 times.
✓ Branch 7 taken 16 times.
|
77 | } else |
| 2855 |
1/2✓ Branch 0 taken 74043 times.
✗ Branch 1 not taken.
|
74043 | return length < get_max_used_key_length(tab->range_scan()); // 5) |
| 2856 | } | ||
| 2857 | } | ||
| 2858 | 1866246 | return false; | |
| 2859 | } | ||
| 2860 | |||
| 2861 | /** | ||
| 2862 | An utility function - apply heuristics and optimize access methods to tables. | ||
| 2863 | Currently this function can change REF to RANGE and ALL to INDEX scan if | ||
| 2864 | latter is considered to be better (not cost-based) than the former. | ||
| 2865 | @note Side effect - this function could set 'Impossible WHERE' zero | ||
| 2866 | result. | ||
| 2867 | */ | ||
| 2868 | |||
| 2869 | 1767393 | void JOIN::adjust_access_methods() { | |
| 2870 |
3/6✓ Branch 0 taken 1767402 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1767443 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1767467 times.
✗ Branch 5 not taken.
|
1767393 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 2871 |
2/2✓ Branch 0 taken 6150592 times.
✓ Branch 1 taken 1767540 times.
|
7918132 | for (uint i = const_tables; i < tables; i++) { |
| 2872 | 6150592 | JOIN_TAB *const tab = best_ref[i]; | |
| 2873 | 6150592 | TABLE_LIST *const tl = tab->table_ref; | |
| 2874 | |||
| 2875 |
2/2✓ Branch 0 taken 1842452 times.
✓ Branch 1 taken 4308215 times.
|
6150592 | if (tab->type() == JT_ALL) { |
| 2876 | /* | ||
| 2877 | It's possible to speedup query by switching from full table scan to | ||
| 2878 | the scan of covering index, due to less data being read. | ||
| 2879 | Prerequisites for this are: | ||
| 2880 | 1) Keyread (i.e index only scan) is allowed (table isn't updated/deleted | ||
| 2881 | from) | ||
| 2882 | 2) Covering indexes are available | ||
| 2883 | 3) This isn't a derived table/materialized view | ||
| 2884 | */ | ||
| 2885 | 1842452 | if (!tab->table()->no_keyread && // 1 | |
| 2886 |
6/6✓ Branch 0 taken 1784623 times.
✓ Branch 1 taken 57849 times.
✓ Branch 2 taken 407814 times.
✓ Branch 3 taken 1376826 times.
✓ Branch 4 taken 407683 times.
✓ Branch 5 taken 1434817 times.
|
2250297 | !tab->table()->covering_keys.is_clear_all() && // 2 |
| 2887 |
2/2✓ Branch 0 taken 407675 times.
✓ Branch 1 taken 150 times.
|
407814 | !tl->uses_materialization()) // 3 |
| 2888 | { | ||
| 2889 | /* | ||
| 2890 | It has turned out that the change commented out below, while speeding | ||
| 2891 | things up for disk-bound loads, slows them down for cases when the data | ||
| 2892 | is in disk cache (see BUG#35850): | ||
| 2893 | // See bug #26447: "Using the clustered index for a table scan | ||
| 2894 | // is always faster than using a secondary index". | ||
| 2895 | if (table->s->primary_key != MAX_KEY && | ||
| 2896 | table->file->primary_key_is_clustered()) | ||
| 2897 | tab->index= table->s->primary_key; | ||
| 2898 | else | ||
| 2899 | tab->index=find_shortest_key(table, & table->covering_keys); | ||
| 2900 | */ | ||
| 2901 |
2/2✓ Branch 0 taken 407461 times.
✓ Branch 1 taken 221 times.
|
407683 | if (tab->position()->sj_strategy != SJ_OPT_LOOSE_SCAN) |
| 2902 | 407470 | tab->set_index( | |
| 2903 | 407461 | find_shortest_key(tab->table(), &tab->table()->covering_keys)); | |
| 2904 | 407653 | tab->set_type(JT_INDEX_SCAN); // Read with index_first / index_next | |
| 2905 | // From table scan to index scan, thus filter effect needs no recalc. | ||
| 2906 |
6/6✓ Branch 0 taken 1376961 times.
✓ Branch 1 taken 57864 times.
✓ Branch 2 taken 1201897 times.
✓ Branch 3 taken 175064 times.
✓ Branch 4 taken 1201897 times.
✓ Branch 5 taken 232928 times.
|
1434817 | } else if (!tab->table()->no_keyread && !tl->uses_materialization()) { |
| 2907 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1201897 times.
|
1201897 | assert(tab->table()->covering_keys.is_clear_all()); |
| 2908 |
1/2✓ Branch 0 taken 1201897 times.
✗ Branch 1 not taken.
|
1201897 | if (tab->position()->sj_strategy != SJ_OPT_LOOSE_SCAN) { |
| 2909 |
1/2✓ Branch 0 taken 1201897 times.
✗ Branch 1 not taken.
|
1201897 | Key_map clustering_keys; |
| 2910 |
2/2✓ Branch 0 taken 1432720 times.
✓ Branch 1 taken 1201897 times.
|
2634617 | for (uint i2 = 0; i2 < tab->table()->s->keys; i2++) { |
| 2911 |
3/4✓ Branch 0 taken 603312 times.
✓ Branch 1 taken 829408 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1432720 times.
|
2036032 | if (tab->keys().is_set(i2) && |
| 2912 |
2/4✓ Branch 0 taken 603312 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 603312 times.
|
603312 | tab->table()->file->index_flags(i2, 0, 0) & HA_CLUSTERED_INDEX) |
| 2913 | ✗ | clustering_keys.set_bit(i2); | |
| 2914 | } | ||
| 2915 |
1/2✓ Branch 0 taken 1201897 times.
✗ Branch 1 not taken.
|
1201897 | uint index = find_shortest_key(tab->table(), &clustering_keys); |
| 2916 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1201897 times.
|
1201897 | if (index != MAX_KEY) { |
| 2917 | ✗ | tab->set_type(JT_INDEX_SCAN); | |
| 2918 | ✗ | tab->set_index(index); | |
| 2919 | } | ||
| 2920 | } | ||
| 2921 | } | ||
| 2922 |
2/2✓ Branch 0 taken 1939989 times.
✓ Branch 1 taken 2368239 times.
|
4308215 | } else if (tab->type() == JT_REF) { |
| 2923 |
2/2✓ Branch 0 taken 1017 times.
✓ Branch 1 taken 1938898 times.
|
1939989 | if (can_switch_from_ref_to_range(thd, tab, ORDER_NOT_RELEVANT, false)) { |
| 2924 | 1017 | tab->set_type(JT_RANGE); | |
| 2925 | |||
| 2926 | 1017 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 2927 |
1/2✓ Branch 0 taken 1017 times.
✗ Branch 1 not taken.
|
1017 | Opt_trace_object wrapper(trace); |
| 2928 |
1/2✓ Branch 0 taken 1017 times.
✗ Branch 1 not taken.
|
2034 | Opt_trace_object(trace, "access_type_changed") |
| 2929 |
1/2✓ Branch 0 taken 1017 times.
✗ Branch 1 not taken.
|
1017 | .add_utf8_table(tl) |
| 2930 | 2034 | .add_utf8("index", | |
| 2931 |
1/2✓ Branch 0 taken 1017 times.
✗ Branch 1 not taken.
|
1017 | tab->table()->key_info[tab->position()->key->key].name) |
| 2932 |
1/2✓ Branch 0 taken 1017 times.
✗ Branch 1 not taken.
|
1017 | .add_alnum("old_type", "ref") |
| 2933 |
1/2✓ Branch 0 taken 1017 times.
✗ Branch 1 not taken.
|
1017 | .add_alnum("new_type", join_type_str[tab->type()]) |
| 2934 |
1/2✓ Branch 0 taken 1017 times.
✗ Branch 1 not taken.
|
1017 | .add_alnum("cause", "uses_more_keyparts"); |
| 2935 | |||
| 2936 | 1017 | tab->use_quick = QS_RANGE; | |
| 2937 | 1017 | tab->position()->filter_effect = COND_FILTER_STALE; | |
| 2938 | 1017 | } else { | |
| 2939 | // Cleanup quick, REF/REF_OR_NULL/EQ_REF, will be clarified later | ||
| 2940 | 1938898 | ::destroy(tab->range_scan()); | |
| 2941 | 1938899 | tab->set_range_scan(nullptr); | |
| 2942 | } | ||
| 2943 | } | ||
| 2944 | // Ensure AM consistency | ||
| 2945 |
4/6✓ Branch 0 taken 33913 times.
✓ Branch 1 taken 6116804 times.
✓ Branch 2 taken 33913 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 33913 times.
✗ Branch 5 not taken.
|
6150688 | assert(!(tab->range_scan() && |
| 2946 | (tab->type() == JT_REF || tab->type() == JT_ALL))); | ||
| 2947 |
5/6✓ Branch 0 taken 6117708 times.
✓ Branch 1 taken 33044 times.
✓ Branch 2 taken 6116842 times.
✓ Branch 3 taken 866 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 33913 times.
|
6150717 | assert((tab->type() != JT_RANGE && tab->type() != JT_INDEX_MERGE) || |
| 2948 | tab->range_scan()); | ||
| 2949 | 6150755 | if (!tab->const_keys.is_clear_all() && | |
| 2950 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 454701 times.
|
454744 | tab->table()->reginfo.impossible_range && |
| 2951 |
5/6✓ Branch 0 taken 21 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 34 times.
|
86 | ((i == const_tables && tab->type() == JT_REF) || |
| 2952 |
2/4✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
|
61 | ((tab->type() == JT_ALL || tab->type() == JT_RANGE || |
| 2953 |
1/2✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
|
18 | tab->type() == JT_INDEX_MERGE || tab->type() == JT_INDEX_SCAN) && |
| 2954 |
5/6✓ Branch 0 taken 454744 times.
✓ Branch 1 taken 5696003 times.
✓ Branch 2 taken 110 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✓ Branch 5 taken 6150637 times.
|
6605528 | tab->use_quick != QS_RANGE)) && |
| 2955 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
110 | !tab->table_ref->is_inner_table_of_outer_join()) |
| 2956 | 37 | zero_result_cause = "Impossible WHERE noticed after reading const tables"; | |
| 2957 | } | ||
| 2958 | 1767540 | } | |
| 2959 | |||
| 2960 | 3733737 | static JOIN_TAB *alloc_jtab_array(THD *thd, uint table_count) { | |
| 2961 |
5/8✓ Branch 0 taken 3733772 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3733815 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6405536 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6405487 times.
✓ Branch 7 taken 3733864 times.
|
10139224 | JOIN_TAB *t = new (thd->mem_root) JOIN_TAB[table_count]; |
| 2962 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3733862 times.
|
3733862 | if (!t) return nullptr; /* purecov: inspected */ |
| 2963 | |||
| 2964 |
5/8✓ Branch 0 taken 3733872 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3733846 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6405298 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6405328 times.
✓ Branch 7 taken 3733816 times.
|
10139160 | QEP_shared *qs = new (thd->mem_root) QEP_shared[table_count]; |
| 2965 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3733816 times.
|
3733816 | if (!qs) return nullptr; /* purecov: inspected */ |
| 2966 | |||
| 2967 |
2/2✓ Branch 0 taken 6405460 times.
✓ Branch 1 taken 3733791 times.
|
10139251 | for (uint i = 0; i < table_count; ++i) t[i].set_qs(qs++); |
| 2968 | |||
| 2969 | 3733791 | return t; | |
| 2970 | } | ||
| 2971 | |||
| 2972 | /** | ||
| 2973 | Set up JOIN_TAB structs according to the picked join order in best_positions. | ||
| 2974 | This allocates execution structures so may be called only after we have the | ||
| 2975 | very final plan. It must be called after | ||
| 2976 | Optimize_table_order::fix_semijoin_strategies(). | ||
| 2977 | |||
| 2978 | @return False if success, True if error | ||
| 2979 | |||
| 2980 | @details | ||
| 2981 | - create join->join_tab array and copy from existing JOIN_TABs in join order | ||
| 2982 | - create helper structs for materialized semi-join handling | ||
| 2983 | - finalize semi-join strategy choices | ||
| 2984 | - Number of intermediate tables "tmp_tables" is calculated. | ||
| 2985 | - "tables" and "primary_tables" are recalculated. | ||
| 2986 | - for full and index scans info of estimated # of records is updated. | ||
| 2987 | - in a helper function: | ||
| 2988 | - all heuristics are applied and the final access method type is picked | ||
| 2989 | for each join_tab (only test_if_skip_sortorder() could override it) | ||
| 2990 | - AM consistency is ensured (e.g only range and index merge are allowed | ||
| 2991 | to have quick select set). | ||
| 2992 | - if "Impossible WHERE" is detected - appropriate zero_result_cause is | ||
| 2993 | set. | ||
| 2994 | |||
| 2995 | Notice that intermediate tables will not have a POSITION reference; and they | ||
| 2996 | will not have a TABLE reference before the final stages of code generation. | ||
| 2997 | |||
| 2998 | @todo the block which sets tab->type should move to adjust_access_methods | ||
| 2999 | for unification. | ||
| 3000 | */ | ||
| 3001 | |||
| 3002 | 1866783 | bool JOIN::get_best_combination() { | |
| 3003 |
1/2✓ Branch 0 taken 1866878 times.
✗ Branch 1 not taken.
|
1866783 | DBUG_TRACE; |
| 3004 | |||
| 3005 | // At this point "tables" and "primary"tables" represent the same: | ||
| 3006 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1866878 times.
|
1866878 | assert(tables == primary_tables); |
| 3007 | |||
| 3008 | /* | ||
| 3009 | Allocate additional space for tmp tables. | ||
| 3010 | Number of plan nodes: | ||
| 3011 | # of regular input tables (including semi-joined ones) + | ||
| 3012 | # of semi-join nests for materialization + | ||
| 3013 | 1? + // For GROUP BY (or implicit grouping when we have windowing) | ||
| 3014 | 1? + // For DISTINCT | ||
| 3015 | 1? + // For aggregation functions aggregated in outer query | ||
| 3016 | // when used with distinct | ||
| 3017 | 1? + // For ORDER BY | ||
| 3018 | 1? // buffer result | ||
| 3019 | |||
| 3020 | Up to 2 tmp tables + N window output tmp are allocated (NOTE: windows also | ||
| 3021 | have frame buffer tmp tables, but those are not relevant here). | ||
| 3022 | */ | ||
| 3023 | uint num_tmp_tables = | ||
| 3024 |
4/4✓ Branch 0 taken 339347 times.
✓ Branch 1 taken 1503922 times.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 339305 times.
|
3710147 | (!group_list.empty() || (implicit_grouping && m_windows.elements > 0) |
| 3025 |
2/2✓ Branch 0 taken 1843269 times.
✓ Branch 1 taken 23550 times.
|
3710088 | ? 1 |
| 3026 | 1866819 | : 0) + | |
| 3027 |
4/4✓ Branch 0 taken 4213 times.
✓ Branch 1 taken 1862606 times.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 4171 times.
|
1866819 | (select_distinct ? (tmp_table_param.outer_sum_func_count ? 2 : 1) : 0) + |
| 3028 |
2/2✓ Branch 0 taken 1315389 times.
✓ Branch 1 taken 551430 times.
|
1866819 | (order.empty() ? 0 : 1) + |
| 3029 | 1866819 | (query_block->active_options() & | |
| 3030 | (SELECT_BIG_RESULT | OPTION_BUFFER_RESULT) | ||
| 3031 |
2/2✓ Branch 0 taken 5771 times.
✓ Branch 1 taken 1861062 times.
|
1866833 | ? 1 |
| 3032 | 1866833 | : 0) + | |
| 3033 | 1866833 | m_windows.elements + 1; /* the presence of windows may increase need for | |
| 3034 | grouping tmp tables, cf. de-optimization | ||
| 3035 | in make_tmp_tables_info | ||
| 3036 | */ | ||
| 3037 |
2/2✓ Branch 0 taken 4900 times.
✓ Branch 1 taken 1861933 times.
|
1866833 | if (num_tmp_tables > (2 + m_windows.elements)) |
| 3038 | 4900 | num_tmp_tables = 2 + m_windows.elements; | |
| 3039 | |||
| 3040 | /* | ||
| 3041 | Rearrange queries with materialized semi-join nests so that the semi-join | ||
| 3042 | nest is replaced with a reference to a materialized temporary table and all | ||
| 3043 | materialized subquery tables are placed after the intermediate tables. | ||
| 3044 | After the following loop, "inner_target" is the position of the first | ||
| 3045 | subquery table (if any). "outer_target" is the position of first outer | ||
| 3046 | table, and will later be used to track the position of any materialized | ||
| 3047 | temporary tables. | ||
| 3048 | */ | ||
| 3049 |
1/2✓ Branch 0 taken 1866865 times.
✗ Branch 1 not taken.
|
1866833 | const bool has_semijoin = !query_block->sj_nests.empty(); |
| 3050 | 1866865 | uint outer_target = 0; | |
| 3051 | 1866865 | uint inner_target = primary_tables + num_tmp_tables; | |
| 3052 | 1866865 | uint sjm_nests = 0; | |
| 3053 | |||
| 3054 |
2/2✓ Branch 0 taken 19226 times.
✓ Branch 1 taken 1847639 times.
|
1866865 | if (has_semijoin) { |
| 3055 |
2/2✓ Branch 0 taken 60018 times.
✓ Branch 1 taken 19226 times.
|
79244 | for (uint tableno = 0; tableno < primary_tables;) { |
| 3056 |
2/2✓ Branch 0 taken 4591 times.
✓ Branch 1 taken 55427 times.
|
60018 | if (sj_is_materialize_strategy(best_positions[tableno].sj_strategy)) { |
| 3057 | 4591 | sjm_nests++; | |
| 3058 | 4591 | inner_target -= (best_positions[tableno].n_sj_tables - 1); | |
| 3059 | 4591 | tableno += best_positions[tableno].n_sj_tables; | |
| 3060 | } else | ||
| 3061 | 55427 | tableno++; | |
| 3062 | } | ||
| 3063 | } | ||
| 3064 | |||
| 3065 | 1866865 | JOIN_TAB *tmp_join_tabs = nullptr; | |
| 3066 |
2/2✓ Branch 0 taken 1866811 times.
✓ Branch 1 taken 54 times.
|
1866865 | if (sjm_nests + num_tmp_tables) { |
| 3067 | // join_tab array only has "primary_tables" tables. We need those more: | ||
| 3068 |
2/4✓ Branch 0 taken 1866867 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1866867 times.
|
1866811 | if (!(tmp_join_tabs = alloc_jtab_array(thd, sjm_nests + num_tmp_tables))) |
| 3069 | ✗ | return true; /* purecov: inspected */ | |
| 3070 | } | ||
| 3071 | |||
| 3072 | // To check that we fill the array correctly: fill it with zeros first | ||
| 3073 | 1866921 | memset(best_ref, 0, | |
| 3074 | 1866921 | sizeof(JOIN_TAB *) * (primary_tables + sjm_nests + num_tmp_tables)); | |
| 3075 | |||
| 3076 | 1866921 | int sjm_index = tables; // Number assigned to materialized temporary table | |
| 3077 | 1866921 | int remaining_sjm_inner = 0; | |
| 3078 | 1866921 | bool err = false; | |
| 3079 |
2/2✓ Branch 0 taken 3951136 times.
✓ Branch 1 taken 1867022 times.
|
5818158 | for (uint tableno = 0; tableno < tables; tableno++) { |
| 3080 | 3951136 | POSITION *const pos = best_positions + tableno; | |
| 3081 |
6/6✓ Branch 0 taken 63886 times.
✓ Branch 1 taken 3887250 times.
✓ Branch 2 taken 4591 times.
✓ Branch 3 taken 59295 times.
✓ Branch 4 taken 4591 times.
✓ Branch 5 taken 3946545 times.
|
3951136 | if (has_semijoin && sj_is_materialize_strategy(pos->sj_strategy)) { |
| 3082 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4591 times.
|
4591 | assert(outer_target < inner_target); |
| 3083 | |||
| 3084 | 4591 | TABLE_LIST *const sj_nest = pos->table->emb_sj_nest; | |
| 3085 | |||
| 3086 | // Handle this many inner tables of materialized semi-join | ||
| 3087 | 4591 | remaining_sjm_inner = pos->n_sj_tables; | |
| 3088 | |||
| 3089 | /* | ||
| 3090 | If we fail in some allocation below, we cannot bail out immediately; | ||
| 3091 | that would put us in a difficult situation to clean up; imagine we | ||
| 3092 | have planned this layout: | ||
| 3093 | outer1 - sj_mat_tmp1 - outer2 - sj_mat_tmp2 - outer3 | ||
| 3094 | We have successfully filled a JOIN_TAB for sj_mat_tmp1, and are | ||
| 3095 | failing to fill a JOIN_TAB for sj_mat_tmp2 (OOM). So we want to quit | ||
| 3096 | this function, which will lead to cleanup functions. | ||
| 3097 | But sj_mat_tmp1 is in this->best_ref only, outer3 is in this->join_tab | ||
| 3098 | only: what is the array to traverse for cleaning up? What is the | ||
| 3099 | number of tables to loop over? | ||
| 3100 | So: if we fail in the present loop, we record the error but continue | ||
| 3101 | filling best_ref; when it's fully filled, bail out, because then | ||
| 3102 | best_ref can be used as reliable array for cleaning up. | ||
| 3103 | */ | ||
| 3104 | 4591 | JOIN_TAB *const tab = tmp_join_tabs++; | |
| 3105 | 4591 | best_ref[outer_target] = tab; | |
| 3106 | 4591 | tab->set_join(this); | |
| 3107 | 4591 | tab->set_idx(outer_target); | |
| 3108 | |||
| 3109 | /* | ||
| 3110 | Up to this point there cannot be a failure. JOIN_TAB has been filled | ||
| 3111 | enough to be clean-able. | ||
| 3112 | */ | ||
| 3113 | |||
| 3114 | 4591 | Semijoin_mat_exec *const sjm_exec = new (thd->mem_root) Semijoin_mat_exec( | |
| 3115 | 4591 | sj_nest, (pos->sj_strategy == SJ_OPT_MATERIALIZE_SCAN), | |
| 3116 |
2/4✓ Branch 0 taken 4591 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4591 times.
✗ Branch 3 not taken.
|
4591 | remaining_sjm_inner, outer_target, inner_target); |
| 3117 | |||
| 3118 | 4591 | tab->set_sj_mat_exec(sjm_exec); | |
| 3119 | |||
| 3120 |
3/6✓ Branch 0 taken 4591 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4591 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4591 times.
|
9182 | if (!sjm_exec || setup_semijoin_materialized_table( |
| 3121 |
1/2✓ Branch 0 taken 4591 times.
✗ Branch 1 not taken.
|
4591 | tab, sjm_index, pos, best_positions + sjm_index)) |
| 3122 | ✗ | err = true; /* purecov: inspected */ | |
| 3123 | |||
| 3124 | 4591 | outer_target++; | |
| 3125 | 4591 | sjm_index++; | |
| 3126 | } | ||
| 3127 | /* | ||
| 3128 | Locate join_tab target for the table we are considering. | ||
| 3129 | (remaining_sjm_inner becomes negative for non-SJM tables, this can be | ||
| 3130 | safely ignored). | ||
| 3131 | */ | ||
| 3132 | const uint target = | ||
| 3133 |
2/2✓ Branch 0 taken 8459 times.
✓ Branch 1 taken 3942677 times.
|
3951136 | (remaining_sjm_inner--) > 0 ? inner_target++ : outer_target++; |
| 3134 | 3951136 | JOIN_TAB *const tab = pos->table; | |
| 3135 | |||
| 3136 | 3951136 | best_ref[target] = tab; | |
| 3137 | 3951136 | tab->set_idx(target); | |
| 3138 | 3951161 | tab->set_position(pos); | |
| 3139 | 3951220 | TABLE *const table = tab->table(); | |
| 3140 |
6/6✓ Branch 0 taken 3859941 times.
✓ Branch 1 taken 91299 times.
✓ Branch 2 taken 3810844 times.
✓ Branch 3 taken 49108 times.
✓ Branch 4 taken 3810848 times.
✓ Branch 5 taken 140403 times.
|
3951231 | if (tab->type() != JT_CONST && tab->type() != JT_SYSTEM) { |
| 3141 |
6/6✓ Branch 0 taken 271 times.
✓ Branch 1 taken 3810577 times.
✓ Branch 2 taken 71 times.
✓ Branch 3 taken 200 times.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 3810804 times.
|
3810911 | if (pos->sj_strategy == SJ_OPT_LOOSE_SCAN && tab->range_scan() && |
| 3142 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 27 times.
|
71 | used_index(tab->range_scan()) != pos->loosescan_key) { |
| 3143 | /* | ||
| 3144 | We must use the duplicate-eliminating index, so this QUICK is not | ||
| 3145 | an option. | ||
| 3146 | */ | ||
| 3147 | 36 | ::destroy(tab->range_scan()); | |
| 3148 | 36 | tab->set_range_scan(nullptr); | |
| 3149 | } | ||
| 3150 |
2/2✓ Branch 0 taken 1873325 times.
✓ Branch 1 taken 1937510 times.
|
3810835 | if (!pos->key) { |
| 3151 |
2/2✓ Branch 0 taken 32896 times.
✓ Branch 1 taken 1840435 times.
|
1873325 | if (tab->range_scan()) |
| 3152 |
1/2✓ Branch 0 taken 32896 times.
✗ Branch 1 not taken.
|
32896 | tab->set_type(calc_join_type(tab->range_scan())); |
| 3153 | else | ||
| 3154 | 1840435 | tab->set_type(JT_ALL); | |
| 3155 | } else | ||
| 3156 | // REF or RANGE, clarify later when prefix tables are set for JOIN_TABs | ||
| 3157 | 1937510 | tab->set_type(JT_REF); | |
| 3158 | } | ||
| 3159 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3951234 times.
|
3951227 | assert(tab->type() != JT_UNKNOWN); |
| 3160 | |||
| 3161 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3951234 times.
|
3951234 | assert(table->reginfo.join_tab == tab); |
| 3162 |
2/2✓ Branch 0 taken 3424325 times.
✓ Branch 1 taken 526908 times.
|
3951234 | if (!tab->join_cond()) |
| 3163 | 3424325 | table->reginfo.not_exists_optimize = false; // Only with LEFT JOIN | |
| 3164 | 3951233 | map2table[tab->table_ref->tableno()] = tab; | |
| 3165 | } | ||
| 3166 | |||
| 3167 | // Count the materialized semi-join tables as regular input tables | ||
| 3168 | 1867022 | tables += sjm_nests + num_tmp_tables; | |
| 3169 | // Set the number of non-materialized tables: | ||
| 3170 | 1867022 | primary_tables = outer_target; | |
| 3171 | |||
| 3172 | /* | ||
| 3173 | Between the last outer table or sj-mat tmp table, and the first sj-mat | ||
| 3174 | inner table, there may be 2 slots for sort/group/etc tmp tables: | ||
| 3175 | */ | ||
| 3176 |
2/2✓ Branch 0 taken 2449542 times.
✓ Branch 1 taken 1867022 times.
|
4316564 | for (uint i = 0; i < num_tmp_tables; ++i) { |
| 3177 | 2449542 | const uint idx = outer_target + i; | |
| 3178 | 2449542 | tmp_join_tabs->set_join(this); | |
| 3179 | 2449541 | tmp_join_tabs->set_idx(idx); | |
| 3180 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2449542 times.
|
2449542 | assert(best_ref[idx] == nullptr); // verify that not overwriting |
| 3181 | 2449542 | best_ref[idx] = tmp_join_tabs++; | |
| 3182 | /* | ||
| 3183 | note that set_table() cannot be called yet. We may not even use this | ||
| 3184 | JOIN_TAB in the end, it's dummy at the moment. Which can be tested with | ||
| 3185 | "position()!=NULL". | ||
| 3186 | */ | ||
| 3187 | } | ||
| 3188 | |||
| 3189 | // make array unreachable: should walk JOIN_TABs by best_ref now | ||
| 3190 | 1867022 | join_tab = nullptr; | |
| 3191 | |||
| 3192 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1867022 times.
|
1867022 | if (err) return true; /* purecov: inspected */ |
| 3193 | |||
| 3194 |
2/2✓ Branch 0 taken 19226 times.
✓ Branch 1 taken 1847796 times.
|
1867022 | if (has_semijoin) { |
| 3195 |
1/2✓ Branch 0 taken 19226 times.
✗ Branch 1 not taken.
|
19226 | set_semijoin_info(); |
| 3196 | |||
| 3197 | // Update equalities and keyuses after having added SJ materialization | ||
| 3198 |
2/4✓ Branch 0 taken 19226 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19226 times.
|
19226 | if (update_equalities_for_sjm()) return true; |
| 3199 | } | ||
| 3200 |
2/2✓ Branch 0 taken 1767452 times.
✓ Branch 1 taken 99394 times.
|
1867022 | if (!plan_is_const()) { |
| 3201 | // Assign map of "available" tables to all tables belonging to query block | ||
| 3202 |
1/2✓ Branch 0 taken 1767481 times.
✗ Branch 1 not taken.
|
1767452 | set_prefix_tables(); |
| 3203 |
1/2✓ Branch 0 taken 1767483 times.
✗ Branch 1 not taken.
|
1767481 | adjust_access_methods(); |
| 3204 | } | ||
| 3205 | // Calculate outer join info | ||
| 3206 |
3/4✓ Branch 0 taken 195268 times.
✓ Branch 1 taken 1671609 times.
✓ Branch 2 taken 195259 times.
✗ Branch 3 not taken.
|
1866877 | if (query_block->outer_join) make_outerjoin_info(); |
| 3207 | |||
| 3208 | // sjm is no longer needed, trash it. To reuse it, reset its members! | ||
| 3209 |
7/12✓ Branch 0 taken 1866882 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1866884 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19861 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 19861 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1886743 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 19861 times.
✓ Branch 11 taken 1866882 times.
|
1886729 | for (TABLE_LIST *sj_nest : query_block->sj_nests) { |
| 3210 | 19861 | TRASH(static_cast<void *>(&sj_nest->nested_join->sjm), | |
| 3211 | sizeof(sj_nest->nested_join->sjm)); | ||
| 3212 | } | ||
| 3213 | |||
| 3214 | 1866882 | return false; | |
| 3215 | 1866882 | } | |
| 3216 | |||
| 3217 | /** | ||
| 3218 | Finds the dependencies of the remaining lateral derived tables. | ||
| 3219 | |||
| 3220 | @param plan_tables map of all tables that the planner is processing | ||
| 3221 | (tables already in plan and tables to be added to plan). | ||
| 3222 | @param idx index of the table which the planner is currently | ||
| 3223 | considering. | ||
| 3224 | @return A map of the dependencies of the remaining | ||
| 3225 | lateral derived tables (from best_ref[idx] and on). | ||
| 3226 | */ | ||
| 3227 | 7598 | table_map JOIN::calculate_deps_of_remaining_lateral_derived_tables( | |
| 3228 | table_map plan_tables, uint idx) const { | ||
| 3229 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7598 times.
|
7598 | assert(has_lateral); |
| 3230 | 7598 | table_map deps = 0; | |
| 3231 | 7598 | auto last = best_ref + tables; | |
| 3232 |
2/2✓ Branch 0 taken 26548 times.
✓ Branch 1 taken 7598 times.
|
34146 | for (auto **pos = best_ref + idx; pos < last; pos++) { |
| 3233 |
6/6✓ Branch 0 taken 25885 times.
✓ Branch 1 taken 663 times.
✓ Branch 2 taken 25876 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 25876 times.
✓ Branch 5 taken 672 times.
|
26548 | if ((*pos)->table_ref && ((*pos)->table_ref->map() & plan_tables)) { |
| 3234 | 25876 | deps |= get_lateral_deps(**pos); | |
| 3235 | } | ||
| 3236 | } | ||
| 3237 | 7598 | return deps; | |
| 3238 | } | ||
| 3239 | |||
| 3240 | /* | ||
| 3241 | Revise usage of join buffer for the specified table and the whole nest | ||
| 3242 | |||
| 3243 | SYNOPSIS | ||
| 3244 | revise_cache_usage() | ||
| 3245 | tab join table for which join buffer usage is to be revised | ||
| 3246 | |||
| 3247 | DESCRIPTION | ||
| 3248 | The function revise the decision to use a join buffer for the table 'tab'. | ||
| 3249 | If this table happened to be among the inner tables of a nested outer join/ | ||
| 3250 | semi-join the functions denies usage of join buffers for all of them | ||
| 3251 | |||
| 3252 | RETURN | ||
| 3253 | none | ||
| 3254 | */ | ||
| 3255 | |||
| 3256 | 1915684 | static void revise_cache_usage(JOIN_TAB *join_tab) { | |
| 3257 | 1915684 | plan_idx first_inner = join_tab->first_inner(); | |
| 3258 | 1915731 | JOIN *const join = join_tab->join(); | |
| 3259 |
2/2✓ Branch 0 taken 522899 times.
✓ Branch 1 taken 1392850 times.
|
1915749 | if (first_inner != NO_PLAN_IDX) { |
| 3260 | 522899 | plan_idx end_tab = join_tab->idx(); | |
| 3261 |
2/2✓ Branch 0 taken 523459 times.
✓ Branch 1 taken 522900 times.
|
1046350 | for (first_inner = join_tab->first_inner(); first_inner != NO_PLAN_IDX; |
| 3262 | 523459 | first_inner = join->best_ref[first_inner]->first_upper()) { | |
| 3263 |
2/2✓ Branch 0 taken 4825 times.
✓ Branch 1 taken 523459 times.
|
528284 | for (plan_idx i = end_tab - 1; i >= first_inner; --i) |
| 3264 | 4825 | join->best_ref[i]->set_use_join_cache(JOIN_CACHE::ALG_NONE); | |
| 3265 | 523459 | end_tab = first_inner; | |
| 3266 | } | ||
| 3267 |
2/2✓ Branch 0 taken 7533 times.
✓ Branch 1 taken 1385274 times.
|
1392850 | } else if (join_tab->get_sj_strategy() == SJ_OPT_FIRST_MATCH) { |
| 3268 | 7533 | plan_idx first_sj_inner = join_tab->first_sj_inner(); | |
| 3269 |
2/2✓ Branch 0 taken 4832 times.
✓ Branch 1 taken 7533 times.
|
12365 | for (plan_idx i = join_tab->idx() - 1; i >= first_sj_inner; --i) { |
| 3270 | 4832 | JOIN_TAB *tab = join->best_ref[i]; | |
| 3271 |
1/2✓ Branch 0 taken 4832 times.
✗ Branch 1 not taken.
|
4832 | if (tab->first_sj_inner() == first_sj_inner) |
| 3272 | 4832 | tab->set_use_join_cache(JOIN_CACHE::ALG_NONE); | |
| 3273 | } | ||
| 3274 | } else | ||
| 3275 | 1385274 | join_tab->set_use_join_cache(JOIN_CACHE::ALG_NONE); | |
| 3276 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1915675 times.
|
1915675 | assert(join->qep_tab == nullptr); |
| 3277 | 1915675 | } | |
| 3278 | |||
| 3279 | /** | ||
| 3280 | Set up join buffering for a specified table, if possible. | ||
| 3281 | |||
| 3282 | @param tab joined table to check join buffer usage for | ||
| 3283 | @param join join for which the check is performed | ||
| 3284 | @param no_jbuf_after don't use join buffering after table with this number | ||
| 3285 | |||
| 3286 | @return false if successful, true if error. | ||
| 3287 | Currently, allocation errors for join cache objects are ignored, | ||
| 3288 | and regular execution is chosen silently. | ||
| 3289 | |||
| 3290 | @details | ||
| 3291 | The function finds out whether the table 'tab' can be joined using a join | ||
| 3292 | buffer. This check is performed after the best execution plan for 'join' | ||
| 3293 | has been chosen. If the function decides that a join buffer can be employed | ||
| 3294 | then it selects the most appropriate join cache type, which later will | ||
| 3295 | be instantiated by init_join_cache(). | ||
| 3296 | If it has already been decided to not use join buffering for this table, | ||
| 3297 | no action is taken. | ||
| 3298 | |||
| 3299 | Often it is already decided that join buffering will be used earlier in | ||
| 3300 | the optimization process, and this will also ensure that the most correct | ||
| 3301 | cost for the operation is calculated, and hence the probability of | ||
| 3302 | choosing an optimal join plan is higher. However, some join buffering | ||
| 3303 | decisions cannot currently be taken before this stage, hence we need this | ||
| 3304 | function to decide the most accurate join buffering strategy. | ||
| 3305 | |||
| 3306 | @todo Long-term it is the goal that join buffering strategy is decided | ||
| 3307 | when the plan is selected. | ||
| 3308 | |||
| 3309 | The result of the check and the type of the join buffer to be used | ||
| 3310 | depend on: | ||
| 3311 | - the access method to access rows of the joined table | ||
| 3312 | - whether the join table is an inner table of an outer join or semi-join | ||
| 3313 | - the optimizer_switch settings for join buffering | ||
| 3314 | - the join 'options'. | ||
| 3315 | In any case join buffer is not used if the number of the joined table is | ||
| 3316 | greater than 'no_jbuf_after'. | ||
| 3317 | |||
| 3318 | If block_nested_loop is turned on, and if all other criteria for using | ||
| 3319 | join buffering is fulfilled (see below), then join buffer is used | ||
| 3320 | for any join operation (inner join, outer join, semi-join) with 'JT_ALL' | ||
| 3321 | access method. In that case, a JOIN_CACHE_BNL type is always employed. | ||
| 3322 | |||
| 3323 | If an index is used to access rows of the joined table and | ||
| 3324 | batched_key_access is on, then a JOIN_CACHE_BKA type is employed. | ||
| 3325 | |||
| 3326 | If the function decides that a join buffer can be used to join the table | ||
| 3327 | 'tab' then it sets @c tab->use_join_cache to reflect the chosen algorithm. | ||
| 3328 | |||
| 3329 | @note | ||
| 3330 | For a nested outer join/semi-join, currently, we either use join buffers for | ||
| 3331 | all inner tables or for none of them. | ||
| 3332 | |||
| 3333 | Join buffering is enabled for a few more cases for secondary engine. | ||
| 3334 | Currently if blocked nested loop(BNL) is employed for join buffering, | ||
| 3335 | it is replaced by hash joins in the executor. So the reasons for disabling | ||
| 3336 | join buffering because of the way BNL works are no more valid. This gives | ||
| 3337 | us an oppotunity to enable join buffering for more cases. However, | ||
| 3338 | we enable it only for secondary engine (in particular for semijoins), | ||
| 3339 | because of the following reasons: | ||
| 3340 | Secondary engine does not care about the cost based decisions | ||
| 3341 | involved in arriving at the best possible semijoin strategy; | ||
| 3342 | because it can only interpret a plan using "FirstMatch" strategy | ||
| 3343 | and can only do table scans. So the choices are very limited. | ||
| 3344 | However, it's not the case for mysql. There are serveral semijoin | ||
| 3345 | stratagies that could be picked. And these are picked based | ||
| 3346 | on the assumption that a nested-loop join(NLJ) would be used because | ||
| 3347 | optimizer currently generates plans only for NLJs and not | ||
| 3348 | hash joins. So, when executor replaces with hash joins, the number | ||
| 3349 | of rows that would be looked into for a particular semijoin strategy | ||
| 3350 | will differ from what the optimizer presumed while picking that | ||
| 3351 | strategy. | ||
| 3352 | For mysql server, we could enable join buffering for more cases, when | ||
| 3353 | a cost model for using hash joins is developed and optimizer could | ||
| 3354 | generate plans for hash joins. | ||
| 3355 | |||
| 3356 | @todo | ||
| 3357 | Support BKA inside SJ-Materialization nests. When doing this, we'll need | ||
| 3358 | to only store sj-inner tables in the join buffer. | ||
| 3359 | @verbatim | ||
| 3360 | JOIN_TAB *first_tab= join->join_tab+join->const_tables; | ||
| 3361 | uint n_tables= i-join->const_tables; | ||
| 3362 | / * | ||
| 3363 | We normally put all preceding tables into the join buffer, except | ||
| 3364 | for the constant tables. | ||
| 3365 | If we're inside a semi-join materialization nest, e.g. | ||
| 3366 | |||
| 3367 | outer_tbl1 outer_tbl2 ( inner_tbl1, inner_tbl2 ) ... | ||
| 3368 | ^-- we're here | ||
| 3369 | |||
| 3370 | then we need to put into the join buffer only the tables from | ||
| 3371 | within the nest. | ||
| 3372 | * / | ||
| 3373 | if (i >= first_sjm_table && i < last_sjm_table) | ||
| 3374 | { | ||
| 3375 | n_tables= i - first_sjm_table; // will be >0 if we got here | ||
| 3376 | first_tab= join->join_tab + first_sjm_table; | ||
| 3377 | } | ||
| 3378 | @endverbatim | ||
| 3379 | */ | ||
| 3380 | |||
| 3381 | 3778391 | static bool setup_join_buffering(JOIN_TAB *tab, JOIN *join, | |
| 3382 | uint no_jbuf_after) { | ||
| 3383 |
3/6✓ Branch 0 taken 3778459 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3778508 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3778525 times.
✗ Branch 5 not taken.
|
3778391 | ASSERT_BEST_REF_IN_JOIN_ORDER(join); |
| 3384 | 3778457 | Cost_estimate cost; | |
| 3385 | ha_rows rows; | ||
| 3386 | 3778499 | uint bufsz = 4096; | |
| 3387 | 3778499 | uint join_cache_flags = 0; | |
| 3388 |
1/2✓ Branch 0 taken 3778507 times.
✗ Branch 1 not taken.
|
3778499 | const bool bnl_on = hint_table_state(join->thd, tab->table_ref, BNL_HINT_ENUM, |
| 3389 | OPTIMIZER_SWITCH_BNL); | ||
| 3390 |
1/2✓ Branch 0 taken 3778540 times.
✗ Branch 1 not taken.
|
3778507 | const bool bka_on = hint_table_state(join->thd, tab->table_ref, BKA_HINT_ENUM, |
| 3391 | OPTIMIZER_SWITCH_BKA); | ||
| 3392 | |||
| 3393 | 3778540 | const uint tableno = tab->idx(); | |
| 3394 |
1/2✓ Branch 0 taken 3778552 times.
✗ Branch 1 not taken.
|
3778532 | const uint tab_sj_strategy = tab->get_sj_strategy(); |
| 3395 | |||
| 3396 | /* | ||
| 3397 | If all key_parts are null_rejecting, the MultiRangeRowIterator will | ||
| 3398 | eliminate all NULL values in the key set, such that | ||
| 3399 | HA_MRR_NO_NULL_ENDPOINTS can be promised. | ||
| 3400 | */ | ||
| 3401 | 3778552 | const key_part_map keypart_map = make_prev_keypart_map(tab->ref().key_parts); | |
| 3402 |
2/2✓ Branch 0 taken 2367587 times.
✓ Branch 1 taken 1410951 times.
|
3778551 | if (tab->ref().null_rejecting == keypart_map) { |
| 3403 | 2367587 | join_cache_flags |= HA_MRR_NO_NULL_ENDPOINTS; | |
| 3404 | } | ||
| 3405 | |||
| 3406 | // Set preliminary join cache setting based on decision from greedy search | ||
| 3407 |
2/2✓ Branch 0 taken 3762583 times.
✓ Branch 1 taken 15955 times.
|
3778538 | if (!join->select_count) |
| 3408 |
2/2✓ Branch 0 taken 156776 times.
✓ Branch 1 taken 3605812 times.
|
3762583 | tab->set_use_join_cache(tab->position()->use_join_buffer |
| 3409 | ? JOIN_CACHE::ALG_BNL | ||
| 3410 | : JOIN_CACHE::ALG_NONE); | ||
| 3411 | |||
| 3412 |
2/2✓ Branch 0 taken 1730973 times.
✓ Branch 1 taken 2047553 times.
|
3778526 | if (tableno == join->const_tables) { |
| 3413 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1730953 times.
|
1730973 | assert(tab->use_join_cache() == JOIN_CACHE::ALG_NONE); |
| 3414 | 1730953 | return false; | |
| 3415 | } | ||
| 3416 | |||
| 3417 |
4/4✓ Branch 0 taken 16789 times.
✓ Branch 1 taken 2030764 times.
✓ Branch 2 taken 616 times.
✓ Branch 3 taken 16173 times.
|
2047553 | if (!(bnl_on || bka_on)) goto no_join_cache; |
| 3418 | |||
| 3419 | /* | ||
| 3420 | psergey-todo: why the below when execution code seems to handle the | ||
| 3421 | "range checked for each record" case? | ||
| 3422 | */ | ||
| 3423 |
2/2✓ Branch 0 taken 519 times.
✓ Branch 1 taken 2046418 times.
|
2046937 | if (tab->use_quick == QS_DYNAMIC_RANGE) goto no_join_cache; |
| 3424 | |||
| 3425 | /* No join buffering if prevented by no_jbuf_after */ | ||
| 3426 |
2/2✓ Branch 0 taken 27683 times.
✓ Branch 1 taken 2018735 times.
|
2046418 | if (tableno > no_jbuf_after) goto no_join_cache; |
| 3427 | |||
| 3428 | /* | ||
| 3429 | An inner table of an outer join nest must not use join buffering if | ||
| 3430 | the first inner table of that outer join nest does not use join buffering. | ||
| 3431 | This condition is not handled by earlier optimizer stages. | ||
| 3432 | */ | ||
| 3433 |
8/8✓ Branch 0 taken 532547 times.
✓ Branch 1 taken 1486189 times.
✓ Branch 2 taken 2962 times.
✓ Branch 3 taken 529581 times.
✓ Branch 4 taken 1605 times.
✓ Branch 5 taken 1337 times.
✓ Branch 6 taken 1605 times.
✓ Branch 7 taken 2017107 times.
|
2021677 | if (tab->first_inner() != NO_PLAN_IDX && tab->first_inner() != tab->idx() && |
| 3434 | 2962 | !join->best_ref[tab->first_inner()]->use_join_cache()) | |
| 3435 | 1605 | goto no_join_cache; | |
| 3436 | /* | ||
| 3437 | The first inner table of an outer join nest must not use join buffering | ||
| 3438 | if the tables in the embedding outer join nest do not use join buffering. | ||
| 3439 | This condition is not handled by earlier optimizer stages. | ||
| 3440 | */ | ||
| 3441 |
6/6✓ Branch 0 taken 809 times.
✓ Branch 1 taken 2016282 times.
✓ Branch 2 taken 382 times.
✓ Branch 3 taken 373 times.
✓ Branch 4 taken 382 times.
✓ Branch 5 taken 2016655 times.
|
2017862 | if (tab->first_upper() != NO_PLAN_IDX && |
| 3442 | 809 | !join->best_ref[tab->first_upper()]->use_join_cache()) | |
| 3443 | 382 | goto no_join_cache; | |
| 3444 | |||
| 3445 |
5/6✓ Branch 0 taken 77 times.
✓ Branch 1 taken 2016633 times.
✓ Branch 2 taken 77 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 77 times.
✓ Branch 5 taken 2016633 times.
|
2016655 | if (tab->table()->pos_in_table_list->is_table_function() && tab->dependent) |
| 3446 | 77 | goto no_join_cache; | |
| 3447 | |||
| 3448 |
5/5✓ Branch 0 taken 9224 times.
✓ Branch 1 taken 112 times.
✓ Branch 2 taken 8381 times.
✓ Branch 3 taken 1998861 times.
✓ Branch 4 taken 55 times.
|
2016633 | switch (tab_sj_strategy) { |
| 3449 | 9224 | case SJ_OPT_FIRST_MATCH: | |
| 3450 | /* | ||
| 3451 | Use join cache with FirstMatch semi-join strategy only when semi-join | ||
| 3452 | contains only one table. | ||
| 3453 | As mentioned earlier (in comments), we lift this restriction for | ||
| 3454 | secondary engine. | ||
| 3455 | */ | ||
| 3456 |
3/6✓ Branch 0 taken 9224 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9224 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9224 times.
✗ Branch 5 not taken.
|
18448 | if (!(current_thd->lex->m_sql_cmd != nullptr && |
| 3457 |
2/4✓ Branch 0 taken 9224 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9224 times.
✗ Branch 3 not taken.
|
9224 | current_thd->lex->m_sql_cmd->using_secondary_storage_engine())) { |
| 3458 |
2/2✓ Branch 0 taken 7245 times.
✓ Branch 1 taken 1979 times.
|
9224 | if (!tab->is_single_inner_of_semi_join()) { |
| 3459 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7245 times.
|
7245 | assert(tab->use_join_cache() == JOIN_CACHE::ALG_NONE); |
| 3460 | 7245 | goto no_join_cache; | |
| 3461 | } | ||
| 3462 | } | ||
| 3463 | 1979 | break; | |
| 3464 | |||
| 3465 | 112 | case SJ_OPT_LOOSE_SCAN: | |
| 3466 | /* No join buffering if this semijoin nest is handled by loosescan */ | ||
| 3467 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
|
112 | assert(tab->use_join_cache() == JOIN_CACHE::ALG_NONE); |
| 3468 | 112 | goto no_join_cache; | |
| 3469 | |||
| 3470 | 8381 | case SJ_OPT_MATERIALIZE_LOOKUP: | |
| 3471 | case SJ_OPT_MATERIALIZE_SCAN: | ||
| 3472 | /* | ||
| 3473 | The Materialize strategies reuse the join_tab belonging to the | ||
| 3474 | first table that was materialized. Neither table can use join buffering: | ||
| 3475 | - The first table in a join never uses join buffering. | ||
| 3476 | - The join_tab used for looking up a row in the materialized table, or | ||
| 3477 | scanning the rows of a materialized table, cannot use join buffering. | ||
| 3478 | We allow join buffering for the remaining tables of the materialized | ||
| 3479 | semi-join nest. | ||
| 3480 | */ | ||
| 3481 |
2/2✓ Branch 0 taken 4561 times.
✓ Branch 1 taken 3820 times.
|
8381 | if (tab->first_sj_inner() == tab->idx()) { |
| 3482 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4561 times.
|
4561 | assert(tab->use_join_cache() == JOIN_CACHE::ALG_NONE); |
| 3483 | 4561 | goto no_join_cache; | |
| 3484 | } | ||
| 3485 | 3820 | break; | |
| 3486 | |||
| 3487 | 1998861 | case SJ_OPT_DUPS_WEEDOUT: | |
| 3488 | // This strategy allows the same join buffering as a regular join would. | ||
| 3489 | case SJ_OPT_NONE: | ||
| 3490 | 1998861 | break; | |
| 3491 | } | ||
| 3492 | |||
| 3493 | /* | ||
| 3494 | The following code prevents use of join buffering when there is an | ||
| 3495 | outer join operation and first match semi-join strategy is used, because: | ||
| 3496 | |||
| 3497 | Outer join needs a "match flag" to track that a row should be | ||
| 3498 | NULL-complemented, such flag being attached to first inner table's cache | ||
| 3499 | (tracks whether the cached row from outer table got a match, in which case | ||
| 3500 | no NULL-complemented row is needed). | ||
| 3501 | |||
| 3502 | FirstMatch also needs a "match flag", such flag is attached to sj inner | ||
| 3503 | table's cache (tracks whether the cached row from outer table already got | ||
| 3504 | a first match in the sj-inner table, in which case we don't need to join | ||
| 3505 | this cached row again) | ||
| 3506 | - but a row in a cache has only one "match flag" | ||
| 3507 | - so if "sj inner table"=="first inner", there is a problem. | ||
| 3508 | |||
| 3509 | As mentioned earlier(in comments), we lift this restriction for | ||
| 3510 | secondary engine. | ||
| 3511 | */ | ||
| 3512 |
5/6✓ Branch 0 taken 2004698 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1989720 times.
✓ Branch 3 taken 14978 times.
✓ Branch 4 taken 2004633 times.
✓ Branch 5 taken 95 times.
|
3994465 | if (!(current_thd->lex->m_sql_cmd != nullptr && |
| 3513 |
3/4✓ Branch 0 taken 1989758 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1989651 times.
✓ Branch 3 taken 99 times.
|
1989720 | current_thd->lex->m_sql_cmd->using_secondary_storage_engine())) { |
| 3514 |
6/6✓ Branch 0 taken 1979 times.
✓ Branch 1 taken 2002654 times.
✓ Branch 2 taken 118 times.
✓ Branch 3 taken 1861 times.
✓ Branch 4 taken 118 times.
✓ Branch 5 taken 2004515 times.
|
2006612 | if (tab_sj_strategy == SJ_OPT_FIRST_MATCH && |
| 3515 | 1979 | tab->is_inner_table_of_outer_join()) | |
| 3516 | 118 | goto no_join_cache; | |
| 3517 | } | ||
| 3518 | |||
| 3519 | 4009248 | if (join->deps_of_remaining_lateral_derived_tables & | |
| 3520 |
2/2✓ Branch 0 taken 593 times.
✓ Branch 1 taken 2004045 times.
|
2004610 | (tab->prefix_tables() & ~tab->added_tables())) { |
| 3521 | /* | ||
| 3522 | Even though the planner said "no jbuf please", the switch below may | ||
| 3523 | force it. | ||
| 3524 | If first-dependency-of-lateral-table < table-we-plan-for <= | ||
| 3525 | lateral-table, disable join buffering. | ||
| 3526 | Reason for this rule: | ||
| 3527 | consider a plan t1-t2-dt where dt is LATERAL and depends only on t1, and | ||
| 3528 | imagine t2 could do join buffering: then we buffer many rows of t1, then | ||
| 3529 | read one row of t2, fetch row#1 of t1 from cache, then materialize "dt" | ||
| 3530 | (as it depends on t1) and send row to client; then fetch row#2 of t1 | ||
| 3531 | from cache, rematerialize "dt": it's very inefficient. So we forbid join | ||
| 3532 | buffering on t2; this way, the signal "row of t1 changed" is emitted at | ||
| 3533 | the level of t1's operator, i.e. much less often, as one row of t1 may | ||
| 3534 | serve N rows of t2 before changing. | ||
| 3535 | On the other hand, t1 can do join buffering. | ||
| 3536 | A nice side-effect is to disable join buffering for "dt" itself. If | ||
| 3537 | "dt" would do join buffering: "dt" buffers many rows from t1/t2, then in a | ||
| 3538 | second phase we read one row from "dt" and join it with the many rows | ||
| 3539 | from t1/t2; but we cannot read a row from "dt" without first choosing a | ||
| 3540 | row of t1/t2 as "dt" depends on t1. | ||
| 3541 | See similar code in best_access_path(). | ||
| 3542 | */ | ||
| 3543 | 593 | goto no_join_cache; | |
| 3544 | } | ||
| 3545 | |||
| 3546 |
3/3✓ Branch 0 taken 140083 times.
✓ Branch 1 taken 1863899 times.
✓ Branch 2 taken 73 times.
|
2004045 | switch (tab->type()) { |
| 3547 | 140083 | case JT_ALL: | |
| 3548 | case JT_INDEX_SCAN: | ||
| 3549 | case JT_RANGE: | ||
| 3550 | case JT_INDEX_MERGE: | ||
| 3551 |
2/2✓ Branch 0 taken 8840 times.
✓ Branch 1 taken 131243 times.
|
140083 | if (!bnl_on) { |
| 3552 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8840 times.
|
8840 | assert(tab->use_join_cache() == JOIN_CACHE::ALG_NONE); |
| 3553 | 8840 | goto no_join_cache; | |
| 3554 | } | ||
| 3555 | |||
| 3556 |
2/2✓ Branch 0 taken 131156 times.
✓ Branch 1 taken 87 times.
|
131243 | if (!join->select_count) tab->set_use_join_cache(JOIN_CACHE::ALG_BNL); |
| 3557 | 131243 | return false; | |
| 3558 | 1863899 | case JT_SYSTEM: | |
| 3559 | case JT_CONST: | ||
| 3560 | case JT_REF: | ||
| 3561 | case JT_EQ_REF: | ||
| 3562 |
2/2✓ Branch 0 taken 1858334 times.
✓ Branch 1 taken 5565 times.
|
1863899 | if (!bka_on) { |
| 3563 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 1858304 times.
|
1858334 | assert(tab->use_join_cache() == JOIN_CACHE::ALG_NONE); |
| 3564 | 1858304 | goto no_join_cache; | |
| 3565 | } | ||
| 3566 | |||
| 3567 | /* | ||
| 3568 | Disable BKA for materializable derived tables/views as they aren't | ||
| 3569 | instantiated yet. | ||
| 3570 | */ | ||
| 3571 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 5500 times.
|
5565 | if (tab->table_ref->uses_materialization()) goto no_join_cache; |
| 3572 | |||
| 3573 | /* | ||
| 3574 | Can't use BKA for subquery if dealing with a subquery that can | ||
| 3575 | turn a ref access into a "full scan on NULL key" table scan. | ||
| 3576 | |||
| 3577 | @see Item_in_optimizer::val_int() | ||
| 3578 | @see subselect_iterator_engine::exec() | ||
| 3579 | @see TABLE_REF::cond_guards | ||
| 3580 | @see push_index_cond() | ||
| 3581 | |||
| 3582 | @todo: This choice to not use BKA should be done before making | ||
| 3583 | cost estimates, e.g. in set_join_buffer_properties(). That | ||
| 3584 | happens before cond guards are set up, so instead of doing the | ||
| 3585 | check below, BKA should be disabled if | ||
| 3586 | - We are in an IN subquery, and | ||
| 3587 | - The IN predicate is not a top_level_item, and | ||
| 3588 | - The left_expr of the IN predicate may contain NULL values | ||
| 3589 | (left_expr->maybe_null) | ||
| 3590 | */ | ||
| 3591 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 5452 times.
|
5500 | if (tab->has_guarded_conds()) goto no_join_cache; |
| 3592 | |||
| 3593 |
2/2✓ Branch 0 taken 1884 times.
✓ Branch 1 taken 3568 times.
|
5452 | if (tab->table()->covering_keys.is_set(tab->ref().key)) |
| 3594 | 1884 | join_cache_flags |= HA_MRR_INDEX_ONLY; | |
| 3595 | 5452 | rows = tab->table()->file->multi_range_read_info( | |
| 3596 |
1/2✓ Branch 0 taken 5452 times.
✗ Branch 1 not taken.
|
5452 | tab->ref().key, 10, 20, &bufsz, &join_cache_flags, &cost); |
| 3597 | /* | ||
| 3598 | Cannot use BKA if | ||
| 3599 | 1. MRR scan cannot be performed, or | ||
| 3600 | 2. MRR default implementation is used, or | ||
| 3601 | 3. HA_MRR_NO_ASSOCIATION flag is set | ||
| 3602 | */ | ||
| 3603 |
1/2✓ Branch 0 taken 5452 times.
✗ Branch 1 not taken.
|
5452 | if ((rows == HA_POS_ERROR) || // 1 |
| 3604 |
2/2✓ Branch 0 taken 558 times.
✓ Branch 1 taken 4894 times.
|
5452 | (join_cache_flags & HA_MRR_USE_DEFAULT_IMPL) || // 2 |
| 3605 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 558 times.
|
558 | (join_cache_flags & HA_MRR_NO_ASSOCIATION)) // 3 |
| 3606 | 4894 | goto no_join_cache; | |
| 3607 | |||
| 3608 | 558 | tab->set_use_join_cache(JOIN_CACHE::ALG_BKA); | |
| 3609 | |||
| 3610 | 558 | tab->join_cache_flags = join_cache_flags; | |
| 3611 | 558 | return false; | |
| 3612 | default:; | ||
| 3613 | } | ||
| 3614 | |||
| 3615 | 1915735 | no_join_cache: | |
| 3616 |
1/2✓ Branch 0 taken 1915670 times.
✗ Branch 1 not taken.
|
1915735 | revise_cache_usage(tab); |
| 3617 | 1915670 | tab->set_use_join_cache(JOIN_CACHE::ALG_NONE); | |
| 3618 | 1915710 | return false; | |
| 3619 | } | ||
| 3620 | |||
| 3621 | /***************************************************************************** | ||
| 3622 | Make some simple condition optimization: | ||
| 3623 | If there is a test 'field = const' change all refs to 'field' to 'const' | ||
| 3624 | Remove all dummy tests 'item = item', 'const op const'. | ||
| 3625 | Remove all 'item is NULL', when item can never be null! | ||
| 3626 | Return in cond_value false if condition is impossible (1 = 2) | ||
| 3627 | *****************************************************************************/ | ||
| 3628 | |||
| 3629 | class COND_CMP : public ilink<COND_CMP> { | ||
| 3630 | public: | ||
| 3631 | 52 | static void *operator new(size_t size) { return (*THR_MALLOC)->Alloc(size); } | |
| 3632 | ✗ | static void operator delete(void *ptr [[maybe_unused]], | |
| 3633 | size_t size [[maybe_unused]]) { | ||
| 3634 | ✗ | TRASH(ptr, size); | |
| 3635 | } | ||
| 3636 | |||
| 3637 | Item *and_level; | ||
| 3638 | Item_func *cmp_func; | ||
| 3639 | 52 | COND_CMP(Item *a, Item_func *b) : and_level(a), cmp_func(b) {} | |
| 3640 | }; | ||
| 3641 | |||
| 3642 | 9067711 | Item_equal *find_item_equal(COND_EQUAL *cond_equal, | |
| 3643 | const Item_field *item_field, bool *inherited_fl) { | ||
| 3644 | 9067711 | Item_equal *item = nullptr; | |
| 3645 | 9067711 | bool in_upper_level = false; | |
| 3646 |
2/2✓ Branch 0 taken 10405208 times.
✓ Branch 1 taken 7554870 times.
|
17960078 | while (cond_equal) { |
| 3647 |
1/2✓ Branch 0 taken 10405471 times.
✗ Branch 1 not taken.
|
10405208 | List_iterator_fast<Item_equal> li(cond_equal->current_level); |
| 3648 |
2/2✓ Branch 0 taken 21388858 times.
✓ Branch 1 taken 8892367 times.
|
30281442 | while ((item = li++)) { |
| 3649 |
3/4✓ Branch 0 taken 21389166 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1513195 times.
✓ Branch 3 taken 19875971 times.
|
21388858 | if (item->contains(item_field->field)) goto finish; |
| 3650 | } | ||
| 3651 | 8892367 | in_upper_level = true; | |
| 3652 | 8892367 | cond_equal = cond_equal->upper_levels; | |
| 3653 | } | ||
| 3654 | 7554870 | in_upper_level = false; | |
| 3655 | 9068065 | finish: | |
| 3656 | 9068065 | *inherited_fl = in_upper_level; | |
| 3657 | 9068065 | return item; | |
| 3658 | } | ||
| 3659 | |||
| 3660 | /** | ||
| 3661 | Get the best field substitution for a given field. | ||
| 3662 | |||
| 3663 | If the field is member of a multiple equality, look up that equality | ||
| 3664 | and return the most appropriate field. Usually this is the equivalenced | ||
| 3665 | field belonging to the outer-most table in the join order, but | ||
| 3666 | @see Item_field::get_subst_item() for details. | ||
| 3667 | Otherwise, return the same field. | ||
| 3668 | |||
| 3669 | @param item_field The field that we are seeking a substitution for. | ||
| 3670 | @param cond_equal multiple equalities to search in | ||
| 3671 | |||
| 3672 | @return The substituted field. | ||
| 3673 | */ | ||
| 3674 | |||
| 3675 | 1846835 | Item_field *get_best_field(Item_field *item_field, COND_EQUAL *cond_equal) { | |
| 3676 | bool dummy; | ||
| 3677 |
1/2✓ Branch 0 taken 1846951 times.
✗ Branch 1 not taken.
|
1846835 | Item_equal *item_eq = find_item_equal(cond_equal, item_field, &dummy); |
| 3678 |
2/2✓ Branch 0 taken 524224 times.
✓ Branch 1 taken 1322727 times.
|
1846951 | if (!item_eq) return item_field; |
| 3679 | |||
| 3680 |
1/2✓ Branch 0 taken 1322730 times.
✗ Branch 1 not taken.
|
1322727 | return item_eq->get_subst_item(item_field); |
| 3681 | } | ||
| 3682 | |||
| 3683 | /** | ||
| 3684 | Check whether an equality can be used to build multiple equalities. | ||
| 3685 | |||
| 3686 | This function first checks whether the equality (left_item=right_item) | ||
| 3687 | is a simple equality i.e. one that equates a field with another field | ||
| 3688 | or a constant (field=field_item or field=const_item). | ||
| 3689 | If this is the case the function looks for a multiple equality | ||
| 3690 | in the lists referenced directly or indirectly by cond_equal inferring | ||
| 3691 | the given simple equality. If it doesn't find any, it builds a multiple | ||
| 3692 | equality that covers the predicate, i.e. the predicate can be inferred | ||
| 3693 | from this multiple equality. | ||
| 3694 | The built multiple equality could be obtained in such a way: | ||
| 3695 | create a binary multiple equality equivalent to the predicate, then | ||
| 3696 | merge it, if possible, with one of old multiple equalities. | ||
| 3697 | This guarantees that the set of multiple equalities covering equality | ||
| 3698 | predicates will be minimal. | ||
| 3699 | |||
| 3700 | EXAMPLE: | ||
| 3701 | For the where condition | ||
| 3702 | @code | ||
| 3703 | WHERE a=b AND b=c AND | ||
| 3704 | (b=2 OR f=e) | ||
| 3705 | @endcode | ||
| 3706 | the check_equality will be called for the following equality | ||
| 3707 | predicates a=b, b=c, b=2 and f=e. | ||
| 3708 | - For a=b it will be called with *cond_equal=(0,[]) and will transform | ||
| 3709 | *cond_equal into (0,[Item_equal(a,b)]). | ||
| 3710 | - For b=c it will be called with *cond_equal=(0,[Item_equal(a,b)]) | ||
| 3711 | and will transform *cond_equal into CE=(0,[Item_equal(a,b,c)]). | ||
| 3712 | - For b=2 it will be called with *cond_equal=(ptr(CE),[]) | ||
| 3713 | and will transform *cond_equal into (ptr(CE),[Item_equal(2,a,b,c)]). | ||
| 3714 | - For f=e it will be called with *cond_equal=(ptr(CE), []) | ||
| 3715 | and will transform *cond_equal into (ptr(CE),[Item_equal(f,e)]). | ||
| 3716 | |||
| 3717 | @note | ||
| 3718 | Now only fields that have the same type definitions (verified by | ||
| 3719 | the Field::eq_def method) are placed to the same multiple equalities. | ||
| 3720 | Because of this some equality predicates are not eliminated and | ||
| 3721 | can be used in the constant propagation procedure. | ||
| 3722 | We could weaken the equality test as soon as at least one of the | ||
| 3723 | equal fields is to be equal to a constant. It would require a | ||
| 3724 | more complicated implementation: we would have to store, in | ||
| 3725 | general case, its own constant for each fields from the multiple | ||
| 3726 | equality. But at the same time it would allow us to get rid | ||
| 3727 | of constant propagation completely: it would be done by the call | ||
| 3728 | to build_equal_items_for_cond. | ||
| 3729 | |||
| 3730 | The implementation does not follow exactly the above rules to | ||
| 3731 | build a new multiple equality for the equality predicate. | ||
| 3732 | If it processes the equality of the form field1=field2, it | ||
| 3733 | looks for multiple equalities me1 containing field1 and me2 containing | ||
| 3734 | field2. If only one of them is found the function expands it with | ||
| 3735 | the lacking field. If multiple equalities for both fields are | ||
| 3736 | found they are merged. If both searches fail a new multiple equality | ||
| 3737 | containing just field1 and field2 is added to the existing | ||
| 3738 | multiple equalities. | ||
| 3739 | If the function processes the predicate of the form field1=const, | ||
| 3740 | it looks for a multiple equality containing field1. If found, the | ||
| 3741 | function checks the constant of the multiple equality. If the value | ||
| 3742 | is unknown, it is setup to const. Otherwise the value is compared with | ||
| 3743 | const and the evaluation of the equality predicate is performed. | ||
| 3744 | When expanding/merging equality predicates from the upper levels | ||
| 3745 | the function first copies them for the current level. It looks | ||
| 3746 | acceptable, as this happens rarely. The implementation without | ||
| 3747 | copying would be much more complicated. | ||
| 3748 | |||
| 3749 | @param thd Thread handler | ||
| 3750 | @param left_item left term of the equality to be checked | ||
| 3751 | @param right_item right term of the equality to be checked | ||
| 3752 | @param item equality item if the equality originates from a condition | ||
| 3753 | predicate, 0 if the equality is the result of row | ||
| 3754 | elimination | ||
| 3755 | @param cond_equal multiple equalities that must hold together with the | ||
| 3756 | equality | ||
| 3757 | @param[out] simple_equality | ||
| 3758 | true if the predicate is a simple equality predicate | ||
| 3759 | to be used for building multiple equalities | ||
| 3760 | false otherwise | ||
| 3761 | |||
| 3762 | @returns false if success, true if error | ||
| 3763 | */ | ||
| 3764 | |||
| 3765 | 5466686 | static bool check_simple_equality(THD *thd, Item *left_item, Item *right_item, | |
| 3766 | Item *item, COND_EQUAL *cond_equal, | ||
| 3767 | bool *simple_equality) { | ||
| 3768 | 5466686 | *simple_equality = false; | |
| 3769 | |||
| 3770 |
4/4✓ Branch 0 taken 307568 times.
✓ Branch 1 taken 5159241 times.
✓ Branch 2 taken 304622 times.
✓ Branch 3 taken 5162155 times.
|
5774222 | if (left_item->type() == Item::REF_ITEM && |
| 3771 |
2/2✓ Branch 0 taken 304597 times.
✓ Branch 1 taken 2939 times.
|
307568 | down_cast<Item_ref *>(left_item)->ref_type() == Item_ref::VIEW_REF) { |
| 3772 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 304609 times.
|
304622 | if (down_cast<Item_ref *>(left_item)->is_outer_reference()) return false; |
| 3773 | 304609 | left_item = left_item->real_item(); | |
| 3774 | } | ||
| 3775 |
4/4✓ Branch 0 taken 10460 times.
✓ Branch 1 taken 5456273 times.
✓ Branch 2 taken 9132 times.
✓ Branch 3 taken 5457615 times.
|
5477270 | if (right_item->type() == Item::REF_ITEM && |
| 3776 |
2/2✓ Branch 0 taken 9132 times.
✓ Branch 1 taken 1342 times.
|
10460 | down_cast<Item_ref *>(right_item)->ref_type() == Item_ref::VIEW_REF) { |
| 3777 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 9108 times.
|
9132 | if (down_cast<Item_ref *>(right_item)->is_outer_reference()) return false; |
| 3778 | 9108 | right_item = right_item->real_item(); | |
| 3779 | } | ||
| 3780 | const Item_field *left_item_field, *right_item_field; | ||
| 3781 | |||
| 3782 | 5466723 | if (left_item->type() == Item::FIELD_ITEM && | |
| 3783 |
3/4✓ Branch 0 taken 2202457 times.
✓ Branch 1 taken 3188920 times.
✓ Branch 2 taken 2202466 times.
✗ Branch 3 not taken.
|
7593789 | right_item->type() == Item::FIELD_ITEM && |
| 3784 |
1/2✓ Branch 0 taken 2202477 times.
✗ Branch 1 not taken.
|
4404930 | (left_item_field = down_cast<const Item_field *>(left_item)) && |
| 3785 | 2202466 | (right_item_field = down_cast<const Item_field *>(right_item)) && | |
| 3786 |
8/8✓ Branch 0 taken 5391325 times.
✓ Branch 1 taken 75370 times.
✓ Branch 2 taken 2201220 times.
✓ Branch 3 taken 1257 times.
✓ Branch 4 taken 2196894 times.
✓ Branch 5 taken 4326 times.
✓ Branch 6 taken 2196895 times.
✓ Branch 7 taken 3269866 times.
|
10858086 | !left_item_field->depended_from && !right_item_field->depended_from) { |
| 3787 | /* The predicate the form field1=field2 is processed */ | ||
| 3788 | |||
| 3789 | 2196895 | const Field *const left_field = left_item_field->field; | |
| 3790 | 2196895 | const Field *const right_field = right_item_field->field; | |
| 3791 | |||
| 3792 |
3/4✓ Branch 0 taken 2196893 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 43937 times.
✓ Branch 3 taken 2152956 times.
|
2196895 | if (!left_field->eq_def(right_field)) return false; |
| 3793 | |||
| 3794 | /* Search for multiple equalities containing field1 and/or field2 */ | ||
| 3795 | bool left_copyfl, right_copyfl; | ||
| 3796 | Item_equal *left_item_equal = | ||
| 3797 |
1/2✓ Branch 0 taken 2152935 times.
✗ Branch 1 not taken.
|
2152956 | find_item_equal(cond_equal, left_item_field, &left_copyfl); |
| 3798 | Item_equal *right_item_equal = | ||
| 3799 |
1/2✓ Branch 0 taken 2152943 times.
✗ Branch 1 not taken.
|
2152935 | find_item_equal(cond_equal, right_item_field, &right_copyfl); |
| 3800 | |||
| 3801 | /* As (NULL=NULL) != TRUE we can't just remove the predicate f=f */ | ||
| 3802 |
3/4✓ Branch 0 taken 2152910 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 254 times.
✓ Branch 3 taken 2152656 times.
|
2152943 | if (left_field->eq(right_field)) /* f = f */ |
| 3803 | { | ||
| 3804 | 254 | *simple_equality = | |
| 3805 |
6/6✓ Branch 0 taken 193 times.
✓ Branch 1 taken 61 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 185 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 68 times.
|
254 | !((left_field->is_nullable() || left_field->table->is_nullable()) && |
| 3806 | !left_item_equal); | ||
| 3807 | 254 | return false; | |
| 3808 | } | ||
| 3809 | |||
| 3810 |
4/4✓ Branch 0 taken 160853 times.
✓ Branch 1 taken 1991803 times.
✓ Branch 2 taken 157 times.
✓ Branch 3 taken 160696 times.
|
2152656 | if (left_item_equal && left_item_equal == right_item_equal) { |
| 3811 | /* | ||
| 3812 | The equality predicate is inference of one of the existing | ||
| 3813 | multiple equalities, i.e the condition is already covered | ||
| 3814 | by upper level equalities | ||
| 3815 | */ | ||
| 3816 | 157 | *simple_equality = true; | |
| 3817 | 157 | return false; | |
| 3818 | } | ||
| 3819 | |||
| 3820 | /* Copy the found multiple equalities at the current level if needed */ | ||
| 3821 |
2/2✓ Branch 0 taken 156983 times.
✓ Branch 1 taken 1995516 times.
|
2152499 | if (left_copyfl) { |
| 3822 | /* left_item_equal of an upper level contains left_item */ | ||
| 3823 |
2/4✓ Branch 0 taken 156974 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 156986 times.
✗ Branch 3 not taken.
|
156983 | left_item_equal = new Item_equal(left_item_equal); |
| 3824 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 156986 times.
|
156986 | if (left_item_equal == nullptr) return true; |
| 3825 |
1/2✓ Branch 0 taken 156978 times.
✗ Branch 1 not taken.
|
156986 | cond_equal->current_level.push_back(left_item_equal); |
| 3826 | } | ||
| 3827 |
2/2✓ Branch 0 taken 413 times.
✓ Branch 1 taken 2152081 times.
|
2152494 | if (right_copyfl) { |
| 3828 | /* right_item_equal of an upper level contains right_item */ | ||
| 3829 |
2/4✓ Branch 0 taken 413 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 413 times.
✗ Branch 3 not taken.
|
413 | right_item_equal = new Item_equal(right_item_equal); |
| 3830 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 413 times.
|
413 | if (right_item_equal == nullptr) return true; |
| 3831 |
1/2✓ Branch 0 taken 378 times.
✗ Branch 1 not taken.
|
413 | cond_equal->current_level.push_back(right_item_equal); |
| 3832 | } | ||
| 3833 | |||
| 3834 |
2/2✓ Branch 0 taken 160682 times.
✓ Branch 1 taken 1991777 times.
|
2152459 | if (left_item_equal) { |
| 3835 | /* left item was found in the current or one of the upper levels */ | ||
| 3836 |
2/2✓ Branch 0 taken 160505 times.
✓ Branch 1 taken 177 times.
|
160682 | if (!right_item_equal) |
| 3837 |
1/2✓ Branch 0 taken 160508 times.
✗ Branch 1 not taken.
|
160505 | left_item_equal->add(down_cast<Item_field *>(right_item)); |
| 3838 | else { | ||
| 3839 | /* Merge two multiple equalities forming a new one */ | ||
| 3840 |
2/4✓ Branch 0 taken 177 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 177 times.
|
177 | if (left_item_equal->merge(thd, right_item_equal)) return true; |
| 3841 | /* Remove the merged multiple equality from the list */ | ||
| 3842 |
1/2✓ Branch 0 taken 177 times.
✗ Branch 1 not taken.
|
177 | List_iterator<Item_equal> li(cond_equal->current_level); |
| 3843 |
2/2✓ Branch 0 taken 154 times.
✓ Branch 1 taken 177 times.
|
331 | while ((li++) != right_item_equal) |
| 3844 | ; | ||
| 3845 |
1/2✓ Branch 0 taken 177 times.
✗ Branch 1 not taken.
|
177 | li.remove(); |
| 3846 | } | ||
| 3847 | } else { | ||
| 3848 | /* left item was not found neither the current nor in upper levels */ | ||
| 3849 |
2/2✓ Branch 0 taken 28374 times.
✓ Branch 1 taken 1963403 times.
|
1991777 | if (right_item_equal) { |
| 3850 |
1/2✓ Branch 0 taken 28376 times.
✗ Branch 1 not taken.
|
28374 | right_item_equal->add(down_cast<Item_field *>(left_item)); |
| 3851 | } else { | ||
| 3852 | /* None of the fields was found in multiple equalities */ | ||
| 3853 | Item_equal *item_equal = | ||
| 3854 | 1963403 | new Item_equal(down_cast<Item_field *>(left_item), | |
| 3855 |
2/4✓ Branch 0 taken 1963439 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1963457 times.
✗ Branch 3 not taken.
|
1963430 | down_cast<Item_field *>(right_item)); |
| 3856 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1963457 times.
|
1963457 | if (item_equal == nullptr) return true; |
| 3857 |
1/2✓ Branch 0 taken 1963453 times.
✗ Branch 1 not taken.
|
1963457 | cond_equal->current_level.push_back(item_equal); |
| 3858 | } | ||
| 3859 | } | ||
| 3860 | 2152514 | *simple_equality = true; | |
| 3861 | 2152514 | return false; | |
| 3862 | } | ||
| 3863 | |||
| 3864 | { | ||
| 3865 | /* The predicate of the form field=const/const=field is processed */ | ||
| 3866 | 3269866 | Item *const_item = nullptr; | |
| 3867 | 3269866 | Item_field *field_item = nullptr; | |
| 3868 |
1/2✓ Branch 0 taken 3194462 times.
✗ Branch 1 not taken.
|
6464315 | if (left_item->type() == Item::FIELD_ITEM && |
| 3869 | 3194382 | (field_item = down_cast<Item_field *>(left_item)) && | |
| 3870 |
6/6✓ Branch 0 taken 3194382 times.
✓ Branch 1 taken 75423 times.
✓ Branch 2 taken 3192993 times.
✓ Branch 3 taken 1469 times.
✓ Branch 4 taken 3175584 times.
✓ Branch 5 taken 94250 times.
|
9657209 | field_item->depended_from == nullptr && |
| 3871 |
2/2✓ Branch 0 taken 3175569 times.
✓ Branch 1 taken 17386 times.
|
3192993 | right_item->const_for_execution()) { |
| 3872 | 3175584 | const_item = right_item; | |
| 3873 |
1/2✓ Branch 0 taken 26388 times.
✗ Branch 1 not taken.
|
120638 | } else if (right_item->type() == Item::FIELD_ITEM && |
| 3874 | 26388 | (field_item = down_cast<Item_field *>(right_item)) && | |
| 3875 |
6/6✓ Branch 0 taken 26388 times.
✓ Branch 1 taken 67877 times.
✓ Branch 2 taken 21820 times.
✓ Branch 3 taken 4568 times.
✓ Branch 4 taken 18635 times.
✓ Branch 5 taken 75630 times.
|
142473 | field_item->depended_from == nullptr && |
| 3876 |
2/2✓ Branch 0 taken 18635 times.
✓ Branch 1 taken 3185 times.
|
21820 | left_item->const_for_execution()) { |
| 3877 | 18635 | const_item = left_item; | |
| 3878 | } | ||
| 3879 | |||
| 3880 | // Don't evaluate subqueries if they are disabled during optimization. | ||
| 3881 |
3/4✓ Branch 0 taken 3194197 times.
✓ Branch 1 taken 75652 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3269899 times.
|
6464096 | if (const_item != nullptr && |
| 3882 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3194247 times.
|
3194265 | !evaluate_during_optimization(const_item, |
| 3883 | 3194197 | thd->lex->current_query_block())) | |
| 3884 | ✗ | return false; | |
| 3885 | |||
| 3886 | /* | ||
| 3887 | If the constant expression contains a reference to the field | ||
| 3888 | (for example, a = (a IS NULL)), we don't want to replace the | ||
| 3889 | field with the constant expression as it makes the predicates | ||
| 3890 | more complex and may introduce cycles in the Item tree. | ||
| 3891 | */ | ||
| 3892 |
3/4✓ Branch 0 taken 3194266 times.
✓ Branch 1 taken 75633 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3269804 times.
|
6464070 | if (const_item != nullptr && |
| 3893 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3194171 times.
|
3194255 | const_item->walk(&Item::find_field_processor, enum_walk::POSTFIX, |
| 3894 | 3194266 | pointer_cast<uchar *>(field_item->field))) | |
| 3895 | ✗ | return false; | |
| 3896 | |||
| 3897 |
6/6✓ Branch 0 taken 3194191 times.
✓ Branch 1 taken 75613 times.
✓ Branch 2 taken 3184092 times.
✓ Branch 3 taken 10148 times.
✓ Branch 4 taken 3184077 times.
✓ Branch 5 taken 85776 times.
|
3269804 | if (const_item && field_item->result_type() == const_item->result_type()) { |
| 3898 |
3/4✓ Branch 0 taken 3184158 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 944175 times.
✓ Branch 3 taken 2239983 times.
|
3184077 | if (field_item->result_type() == STRING_RESULT) { |
| 3899 |
1/2✓ Branch 0 taken 944183 times.
✗ Branch 1 not taken.
|
944175 | const CHARSET_INFO *cs = field_item->field->charset(); |
| 3900 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 944183 times.
|
944183 | if (!item) { |
| 3901 | ✗ | Item_func_eq *const eq_item = new Item_func_eq(left_item, right_item); | |
| 3902 | ✗ | if (eq_item == nullptr || eq_item->set_cmp_func()) return true; | |
| 3903 | ✗ | eq_item->quick_fix_field(); | |
| 3904 | ✗ | item = eq_item; | |
| 3905 | } | ||
| 3906 |
5/6✓ Branch 0 taken 944161 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 940684 times.
✓ Branch 3 taken 3477 times.
✓ Branch 4 taken 269561 times.
✓ Branch 5 taken 674571 times.
|
1884838 | if ((cs != down_cast<Item_func *>(item)->compare_collation()) || |
| 3907 |
3/4✓ Branch 0 taken 940655 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 266084 times.
✓ Branch 3 taken 674571 times.
|
940684 | !cs->coll->propagate(cs, nullptr, 0)) |
| 3908 | 269561 | return false; | |
| 3909 | } | ||
| 3910 | |||
| 3911 | bool copyfl; | ||
| 3912 |
1/2✓ Branch 0 taken 2914564 times.
✗ Branch 1 not taken.
|
2914554 | Item_equal *item_equal = find_item_equal(cond_equal, field_item, ©fl); |
| 3913 |
2/2✓ Branch 0 taken 217 times.
✓ Branch 1 taken 2914347 times.
|
2914564 | if (copyfl) { |
| 3914 |
2/4✓ Branch 0 taken 217 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 217 times.
✗ Branch 3 not taken.
|
217 | item_equal = new Item_equal(item_equal); |
| 3915 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 217 times.
|
217 | if (item_equal == nullptr) return true; |
| 3916 |
1/2✓ Branch 0 taken 189 times.
✗ Branch 1 not taken.
|
217 | cond_equal->current_level.push_back(item_equal); |
| 3917 | } | ||
| 3918 |
2/2✓ Branch 0 taken 772 times.
✓ Branch 1 taken 2913764 times.
|
2914536 | if (item_equal) { |
| 3919 | /* | ||
| 3920 | The flag cond_false will be set to 1 after this, if item_equal | ||
| 3921 | already contains a constant and its value is not equal to | ||
| 3922 | the value of const_item. | ||
| 3923 | */ | ||
| 3924 |
3/4✓ Branch 0 taken 772 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 771 times.
|
772 | if (item_equal->add(thd, const_item, field_item)) return true; |
| 3925 | } else { | ||
| 3926 |
2/4✓ Branch 0 taken 2913808 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2913767 times.
✗ Branch 3 not taken.
|
2913764 | item_equal = new Item_equal(const_item, field_item); |
| 3927 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2913767 times.
|
2913767 | if (item_equal == nullptr) return true; |
| 3928 |
1/2✓ Branch 0 taken 2913845 times.
✗ Branch 1 not taken.
|
2913767 | cond_equal->current_level.push_back(item_equal); |
| 3929 | } | ||
| 3930 | 2914616 | *simple_equality = true; | |
| 3931 | 2914616 | return false; | |
| 3932 | } | ||
| 3933 | } | ||
| 3934 | 85776 | return false; | |
| 3935 | } | ||
| 3936 | |||
| 3937 | /** | ||
| 3938 | Convert row equalities into a conjunction of regular equalities. | ||
| 3939 | |||
| 3940 | The function converts a row equality of the form (E1,...,En)=(E'1,...,E'n) | ||
| 3941 | into a list of equalities E1=E'1,...,En=E'n. For each of these equalities | ||
| 3942 | Ei=E'i the function checks whether it is a simple equality or a row | ||
| 3943 | equality. If it is a simple equality it is used to expand multiple | ||
| 3944 | equalities of cond_equal. If it is a row equality it converted to a | ||
| 3945 | sequence of equalities between row elements. If Ei=E'i is neither a | ||
| 3946 | simple equality nor a row equality the item for this predicate is added | ||
| 3947 | to eq_list. | ||
| 3948 | |||
| 3949 | @param thd thread handle | ||
| 3950 | @param left_row left term of the row equality to be processed | ||
| 3951 | @param right_row right term of the row equality to be processed | ||
| 3952 | @param cond_equal multiple equalities that must hold together with the | ||
| 3953 | predicate | ||
| 3954 | @param eq_list results of conversions of row equalities that are not | ||
| 3955 | simple enough to form multiple equalities | ||
| 3956 | @param[out] simple_equality | ||
| 3957 | true if the row equality is composed of only | ||
| 3958 | simple equalities. | ||
| 3959 | |||
| 3960 | @returns false if conversion succeeded, true if any error. | ||
| 3961 | */ | ||
| 3962 | |||
| 3963 | 68 | static bool check_row_equality(THD *thd, Item *left_row, Item_row *right_row, | |
| 3964 | COND_EQUAL *cond_equal, List<Item> *eq_list, | ||
| 3965 | bool *simple_equality) { | ||
| 3966 | 68 | *simple_equality = false; | |
| 3967 | 68 | uint n = left_row->cols(); | |
| 3968 |
2/2✓ Branch 0 taken 152 times.
✓ Branch 1 taken 68 times.
|
220 | for (uint i = 0; i < n; i++) { |
| 3969 | bool is_converted; | ||
| 3970 |
1/2✓ Branch 0 taken 152 times.
✗ Branch 1 not taken.
|
152 | Item *left_item = left_row->element_index(i); |
| 3971 |
1/2✓ Branch 0 taken 152 times.
✗ Branch 1 not taken.
|
152 | Item *right_item = right_row->element_index(i); |
| 3972 |
3/6✓ Branch 0 taken 152 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 152 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 152 times.
|
152 | if (left_item->type() == Item::ROW_ITEM && |
| 3973 | ✗ | right_item->type() == Item::ROW_ITEM) { | |
| 3974 | ✗ | if (check_row_equality(thd, down_cast<Item_row *>(left_item), | |
| 3975 | down_cast<Item_row *>(right_item), cond_equal, | ||
| 3976 | eq_list, &is_converted)) | ||
| 3977 | ✗ | return true; | |
| 3978 | ✗ | if (!is_converted) thd->lex->current_query_block()->cond_count++; | |
| 3979 | } else { | ||
| 3980 |
2/4✓ Branch 0 taken 152 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 152 times.
|
152 | if (check_simple_equality(thd, left_item, right_item, nullptr, cond_equal, |
| 3981 | &is_converted)) | ||
| 3982 | ✗ | return true; | |
| 3983 | 152 | thd->lex->current_query_block()->cond_count++; | |
| 3984 | } | ||
| 3985 | |||
| 3986 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 140 times.
|
152 | if (!is_converted) { |
| 3987 |
2/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
|
12 | Item_func_eq *const eq_item = new Item_func_eq(left_item, right_item); |
| 3988 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (eq_item == nullptr) return true; |
| 3989 |
2/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
12 | if (eq_item->set_cmp_func()) { |
| 3990 | // Failed to create cmp func -> not only simple equalitities | ||
| 3991 | ✗ | return true; | |
| 3992 | } | ||
| 3993 | 12 | eq_item->quick_fix_field(); | |
| 3994 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | eq_list->push_back(eq_item); |
| 3995 | } | ||
| 3996 | } | ||
| 3997 | 68 | *simple_equality = true; | |
| 3998 | 68 | return false; | |
| 3999 | } | ||
| 4000 | |||
| 4001 | /** | ||
| 4002 | Eliminate row equalities and form multiple equalities predicates. | ||
| 4003 | |||
| 4004 | This function checks whether the item is a simple equality | ||
| 4005 | i.e. the one that equates a field with another field or a constant | ||
| 4006 | (field=field_item or field=constant_item), or, a row equality. | ||
| 4007 | For a simple equality the function looks for a multiple equality | ||
| 4008 | in the lists referenced directly or indirectly by cond_equal inferring | ||
| 4009 | the given simple equality. If it doesn't find any, it builds/expands | ||
| 4010 | multiple equality that covers the predicate. | ||
| 4011 | Row equalities are eliminated substituted for conjunctive regular | ||
| 4012 | equalities which are treated in the same way as original equality | ||
| 4013 | predicates. | ||
| 4014 | |||
| 4015 | @param thd thread handle | ||
| 4016 | @param item predicate to process | ||
| 4017 | @param cond_equal multiple equalities that must hold together with the | ||
| 4018 | predicate | ||
| 4019 | @param eq_list results of conversions of row equalities that are not | ||
| 4020 | simple enough to form multiple equalities | ||
| 4021 | @param[out] equality | ||
| 4022 | true if re-writing rules have been applied | ||
| 4023 | false otherwise, i.e. | ||
| 4024 | if the predicate is not an equality, or | ||
| 4025 | if the equality is neither a simple nor a row equality | ||
| 4026 | |||
| 4027 | @returns false if success, true if error | ||
| 4028 | |||
| 4029 | @note If the equality was created by IN->EXISTS, it may be removed later by | ||
| 4030 | subquery materialization. So we don't mix this possibly temporary equality | ||
| 4031 | with others; if we let it go into a multiple-equality (Item_equal), then we | ||
| 4032 | could not remove it later. There is however an exception: if the outer | ||
| 4033 | expression is a constant, it is safe to leave the equality even in | ||
| 4034 | materialization; all it can do is preventing NULL/FALSE distinction but if | ||
| 4035 | such distinction mattered the equality would be in a triggered condition so | ||
| 4036 | we would not come to this function. And injecting constants is good because | ||
| 4037 | it makes the materialized table smaller. | ||
| 4038 | */ | ||
| 4039 | |||
| 4040 | 8409975 | static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal, | |
| 4041 | List<Item> *eq_list, bool *equality) { | ||
| 4042 | 8409975 | *equality = false; | |
| 4043 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8410094 times.
|
8409975 | assert(item->is_bool_func()); |
| 4044 | Item_func *item_func; | ||
| 4045 |
4/4✓ Branch 0 taken 8402339 times.
✓ Branch 1 taken 7742 times.
✓ Branch 2 taken 5477738 times.
✓ Branch 3 taken 2932205 times.
|
16812295 | if (item->type() == Item::FUNC_ITEM && |
| 4046 |
2/2✓ Branch 0 taken 5477675 times.
✓ Branch 1 taken 2924526 times.
|
8402339 | (item_func = down_cast<Item_func *>(item))->functype() == |
| 4047 | Item_func::EQ_FUNC) { | ||
| 4048 | 5477738 | Item *left_item = item_func->arguments()[0]; | |
| 4049 | 5477717 | Item *right_item = item_func->arguments()[1]; | |
| 4050 | |||
| 4051 |
6/6✓ Branch 0 taken 13609 times.
✓ Branch 1 taken 5464072 times.
✓ Branch 2 taken 11013 times.
✓ Branch 3 taken 2596 times.
✓ Branch 4 taken 11013 times.
✓ Branch 5 taken 5466668 times.
|
5477744 | if (item->created_by_in2exists() && !left_item->const_item()) |
| 4052 | 11013 | return false; // See note above | |
| 4053 | |||
| 4054 |
4/4✓ Branch 0 taken 101 times.
✓ Branch 1 taken 5466525 times.
✓ Branch 2 taken 68 times.
✓ Branch 3 taken 5466564 times.
|
5466775 | if (left_item->type() == Item::ROW_ITEM && |
| 4055 |
2/2✓ Branch 0 taken 68 times.
✓ Branch 1 taken 39 times.
|
101 | right_item->type() == Item::ROW_ITEM) { |
| 4056 | 68 | thd->lex->current_query_block()->cond_count--; | |
| 4057 | 68 | return check_row_equality(thd, down_cast<Item_row *>(left_item), | |
| 4058 | down_cast<Item_row *>(right_item), cond_equal, | ||
| 4059 | 68 | eq_list, equality); | |
| 4060 | } else | ||
| 4061 | 5466564 | return check_simple_equality(thd, left_item, right_item, item, cond_equal, | |
| 4062 | 5466632 | equality); | |
| 4063 | } | ||
| 4064 | |||
| 4065 | 2932205 | return false; | |
| 4066 | } | ||
| 4067 | |||
| 4068 | /** | ||
| 4069 | Replace all equality predicates in a condition by multiple equality items. | ||
| 4070 | |||
| 4071 | At each 'and' level the function detects items for equality predicates | ||
| 4072 | and replaces them by a set of multiple equality items of class Item_equal, | ||
| 4073 | taking into account inherited equalities from upper levels. | ||
| 4074 | If an equality predicate is used not in a conjunction it's just | ||
| 4075 | replaced by a multiple equality predicate. | ||
| 4076 | For each 'and' level the function set a pointer to the inherited | ||
| 4077 | multiple equalities in the cond_equal field of the associated | ||
| 4078 | object of the type Item_cond_and. | ||
| 4079 | The function also traverses the cond tree and for each field reference | ||
| 4080 | sets a pointer to the multiple equality item containing the field, if there | ||
| 4081 | is any. If this multiple equality equates fields to a constant the | ||
| 4082 | function replaces the field reference by the constant in the cases | ||
| 4083 | when the field is not of a string type or when the field reference is | ||
| 4084 | just an argument of a comparison predicate. | ||
| 4085 | The function also determines the maximum number of members in | ||
| 4086 | equality lists of each Item_cond_and object assigning it to | ||
| 4087 | thd->lex->current_query_block()->max_equal_elems. | ||
| 4088 | |||
| 4089 | @note | ||
| 4090 | Multiple equality predicate =(f1,..fn) is equivalent to the conjunction of | ||
| 4091 | f1=f2, .., fn-1=fn. It substitutes any inference from these | ||
| 4092 | equality predicates that is equivalent to the conjunction. | ||
| 4093 | Thus, =(a1,a2,a3) can substitute for ((a1=a3) AND (a2=a3) AND (a2=a1)) as | ||
| 4094 | it is equivalent to ((a1=a2) AND (a2=a3)). | ||
| 4095 | The function always makes a substitution of all equality predicates occurred | ||
| 4096 | in a conjunction for a minimal set of multiple equality predicates. | ||
| 4097 | This set can be considered as a canonical representation of the | ||
| 4098 | sub-conjunction of the equality predicates. | ||
| 4099 | E.g. (t1.a=t2.b AND t2.b>5 AND t1.a=t3.c) is replaced by | ||
| 4100 | (=(t1.a,t2.b,t3.c) AND t2.b>5), not by | ||
| 4101 | (=(t1.a,t2.b) AND =(t1.a,t3.c) AND t2.b>5); | ||
| 4102 | while (t1.a=t2.b AND t2.b>5 AND t3.c=t4.d) is replaced by | ||
| 4103 | (=(t1.a,t2.b) AND =(t3.c=t4.d) AND t2.b>5), | ||
| 4104 | but if additionally =(t4.d,t2.b) is inherited, it | ||
| 4105 | will be replaced by (=(t1.a,t2.b,t3.c,t4.d) AND t2.b>5) | ||
| 4106 | |||
| 4107 | The function performs the substitution in a recursive descent of | ||
| 4108 | the condition tree, passing to the next AND level a chain of multiple | ||
| 4109 | equality predicates which have been built at the upper levels. | ||
| 4110 | The Item_equal items built at the level are attached to other | ||
| 4111 | non-equality conjuncts as a sublist. The pointer to the inherited | ||
| 4112 | multiple equalities is saved in the and condition object (Item_cond_and). | ||
| 4113 | This chain allows us for any field reference occurrence to easily find a | ||
| 4114 | multiple equality that must be held for this occurrence. | ||
| 4115 | For each AND level we do the following: | ||
| 4116 | - scan it for all equality predicate (=) items | ||
| 4117 | - join them into disjoint Item_equal() groups | ||
| 4118 | - process the included OR conditions recursively to do the same for | ||
| 4119 | lower AND levels. | ||
| 4120 | |||
| 4121 | We need to do things in this order as lower AND levels need to know about | ||
| 4122 | all possible Item_equal objects in upper levels. | ||
| 4123 | |||
| 4124 | @param thd thread handle | ||
| 4125 | @param cond condition(expression) where to make replacement | ||
| 4126 | @param[out] retcond returned condition | ||
| 4127 | @param inherited path to all inherited multiple equality items | ||
| 4128 | @param do_inherit whether or not to inherit equalities from other parts | ||
| 4129 | of the condition | ||
| 4130 | |||
| 4131 | @returns false if success, true if error | ||
| 4132 | */ | ||
| 4133 | |||
| 4134 | 4536930 | static bool build_equal_items_for_cond(THD *thd, Item *cond, Item **retcond, | |
| 4135 | COND_EQUAL *inherited, bool do_inherit) { | ||
| 4136 | Item_equal *item_equal; | ||
| 4137 |
1/2✓ Branch 0 taken 4536953 times.
✗ Branch 1 not taken.
|
4536930 | COND_EQUAL cond_equal; |
| 4138 | 4536953 | cond_equal.upper_levels = inherited; | |
| 4139 |
2/4✓ Branch 0 taken 4536913 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4536913 times.
|
4536953 | assert(cond->is_bool_func()); |
| 4140 |
2/4✓ Branch 0 taken 4537098 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4537098 times.
|
4536913 | if (check_stack_overrun(thd, STACK_MIN_SIZE, nullptr)) |
| 4141 | ✗ | return true; // Fatal error flag is set! | |
| 4142 | |||
| 4143 |
1/2✓ Branch 0 taken 4536993 times.
✗ Branch 1 not taken.
|
4537098 | const enum Item::Type cond_type = cond->type(); |
| 4144 |
2/2✓ Branch 0 taken 1848692 times.
✓ Branch 1 taken 2688301 times.
|
4536993 | if (cond_type == Item::COND_ITEM) { |
| 4145 | 1848692 | List<Item> eq_list; | |
| 4146 | 1848692 | Item_cond *const item_cond = down_cast<Item_cond *>(cond); | |
| 4147 |
1/2✓ Branch 0 taken 1848691 times.
✗ Branch 1 not taken.
|
1848677 | const bool and_level = item_cond->functype() == Item_func::COND_AND_FUNC; |
| 4148 | 1848691 | List<Item> *args = item_cond->argument_list(); | |
| 4149 | |||
| 4150 |
1/2✓ Branch 0 taken 1848688 times.
✗ Branch 1 not taken.
|
1848683 | List_iterator<Item> li(*args); |
| 4151 | Item *item; | ||
| 4152 | |||
| 4153 |
2/2✓ Branch 0 taken 1818312 times.
✓ Branch 1 taken 30376 times.
|
1848688 | if (and_level) { |
| 4154 | /* | ||
| 4155 | Retrieve all conjuncts of this level detecting the equality | ||
| 4156 | that are subject to substitution by multiple equality items and | ||
| 4157 | removing each such predicate from the conjunction after having | ||
| 4158 | found/created a multiple equality whose inference the predicate is. | ||
| 4159 | */ | ||
| 4160 |
2/2✓ Branch 0 taken 5722452 times.
✓ Branch 1 taken 1818288 times.
|
7540728 | while ((item = li++)) { |
| 4161 | /* | ||
| 4162 | PS/SP note: we can safely remove a node from AND-OR | ||
| 4163 | structure here because it's restored before each | ||
| 4164 | re-execution of any prepared statement/stored procedure. | ||
| 4165 | */ | ||
| 4166 | bool equality; | ||
| 4167 |
3/4✓ Branch 0 taken 5722386 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5722385 times.
|
5722452 | if (check_equality(thd, item, &cond_equal, &eq_list, &equality)) |
| 4168 | 1 | return true; | |
| 4169 |
3/4✓ Branch 0 taken 4244189 times.
✓ Branch 1 taken 1478196 times.
✓ Branch 2 taken 4244220 times.
✗ Branch 3 not taken.
|
5722385 | if (equality) li.remove(); |
| 4170 | } | ||
| 4171 | |||
| 4172 | /* | ||
| 4173 | Check if we eliminated all the predicates of the level, e.g. | ||
| 4174 | (a=a AND b=b AND a=a). | ||
| 4175 | */ | ||
| 4176 |
4/4✓ Branch 0 taken 1182440 times.
✓ Branch 1 taken 635848 times.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 1182395 times.
|
1818288 | if (!args->elements && !cond_equal.current_level.elements && |
| 4177 |
1/2✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
|
45 | !eq_list.elements) { |
| 4178 |
1/2✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
|
90 | *retcond = new Item_func_true(); |
| 4179 | 45 | return *retcond == nullptr; | |
| 4180 | } | ||
| 4181 | |||
| 4182 |
1/2✓ Branch 0 taken 1818268 times.
✗ Branch 1 not taken.
|
1818243 | List_iterator_fast<Item_equal> it(cond_equal.current_level); |
| 4183 |
2/2✓ Branch 0 taken 4211442 times.
✓ Branch 1 taken 1818255 times.
|
6029720 | while ((item_equal = it++)) { |
| 4184 |
2/4✓ Branch 0 taken 4211422 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4211422 times.
|
4211442 | if (item_equal->resolve_type(thd)) return true; |
| 4185 |
1/2✓ Branch 0 taken 4211493 times.
✗ Branch 1 not taken.
|
4211422 | item_equal->update_used_tables(); |
| 4186 | 8422900 | thd->lex->current_query_block()->max_equal_elems = | |
| 4187 | 4211482 | std::max(thd->lex->current_query_block()->max_equal_elems, | |
| 4188 |
1/2✓ Branch 0 taken 4211497 times.
✗ Branch 1 not taken.
|
8422945 | item_equal->members()); |
| 4189 | } | ||
| 4190 | |||
| 4191 | 1818255 | Item_cond_and *const item_cond_and = down_cast<Item_cond_and *>(cond); | |
| 4192 |
1/2✓ Branch 0 taken 1818250 times.
✗ Branch 1 not taken.
|
1818258 | item_cond_and->cond_equal = cond_equal; |
| 4193 | 1818250 | inherited = &item_cond_and->cond_equal; | |
| 4194 | } | ||
| 4195 | /* | ||
| 4196 | Make replacement of equality predicates for lower levels | ||
| 4197 | of the condition expression. | ||
| 4198 | */ | ||
| 4199 | 1848626 | li.rewind(); | |
| 4200 |
2/2✓ Branch 0 taken 2505402 times.
✓ Branch 1 taken 1848645 times.
|
4354021 | while ((item = li++)) { |
| 4201 | Item *new_item; | ||
| 4202 |
2/4✓ Branch 0 taken 2505379 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2505379 times.
|
2505402 | if (build_equal_items_for_cond(thd, item, &new_item, inherited, |
| 4203 | do_inherit)) | ||
| 4204 | ✗ | return true; | |
| 4205 |
2/2✓ Branch 0 taken 13085 times.
✓ Branch 1 taken 2492294 times.
|
2505379 | if (new_item != item) { |
| 4206 | /* This replacement happens only for standalone equalities */ | ||
| 4207 | /* | ||
| 4208 | This is ok with PS/SP as the replacement is done for | ||
| 4209 | arguments of an AND/OR item, which are restored for each | ||
| 4210 | execution of PS/SP. | ||
| 4211 | */ | ||
| 4212 | 13085 | li.replace(new_item); | |
| 4213 | } | ||
| 4214 | } | ||
| 4215 |
2/2✓ Branch 0 taken 1818265 times.
✓ Branch 1 taken 30380 times.
|
1848645 | if (and_level) { |
| 4216 |
1/2✓ Branch 0 taken 1818243 times.
✗ Branch 1 not taken.
|
1818265 | args->concat(&eq_list); |
| 4217 |
1/2✓ Branch 0 taken 1818268 times.
✗ Branch 1 not taken.
|
1818243 | args->concat((List<Item> *)&cond_equal.current_level); |
| 4218 | } | ||
| 4219 |
3/4✓ Branch 0 taken 2688280 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2687612 times.
✓ Branch 3 taken 668 times.
|
2688301 | } else if (cond->type() == Item::FUNC_ITEM) { |
| 4220 | 2687612 | List<Item> eq_list; | |
| 4221 | /* | ||
| 4222 | If an equality predicate forms the whole and level, | ||
| 4223 | we call it standalone equality and it's processed here. | ||
| 4224 | E.g. in the following where condition | ||
| 4225 | WHERE a=5 AND (b=5 or a=c) | ||
| 4226 | (b=5) and (a=c) are standalone equalities. | ||
| 4227 | In general we can't leave alone standalone eqalities: | ||
| 4228 | for WHERE a=b AND c=d AND (b=c OR d=5) | ||
| 4229 | b=c is replaced by =(a,b,c,d). | ||
| 4230 | */ | ||
| 4231 | bool equality; | ||
| 4232 |
2/4✓ Branch 0 taken 2687619 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2687619 times.
|
2687612 | if (check_equality(thd, cond, &cond_equal, &eq_list, &equality)) |
| 4233 | 823117 | return true; | |
| 4234 |
2/2✓ Branch 0 taken 823183 times.
✓ Branch 1 taken 1864436 times.
|
2687619 | if (equality) { |
| 4235 | 823183 | int n = cond_equal.current_level.elements + eq_list.elements; | |
| 4236 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 823158 times.
|
823183 | if (n == 0) { |
| 4237 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
50 | *retcond = new Item_func_true(); |
| 4238 | 25 | return *retcond == nullptr; | |
| 4239 |
2/2✓ Branch 0 taken 823094 times.
✓ Branch 1 taken 64 times.
|
823158 | } else if (n == 1) { |
| 4240 |
2/2✓ Branch 0 taken 823040 times.
✓ Branch 1 taken 20 times.
|
823094 | if ((item_equal = cond_equal.current_level.pop())) { |
| 4241 |
2/4✓ Branch 0 taken 823042 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 823042 times.
|
823040 | if (item_equal->resolve_type(thd)) return true; |
| 4242 |
1/2✓ Branch 0 taken 823085 times.
✗ Branch 1 not taken.
|
823042 | item_equal->update_used_tables(); |
| 4243 | 1646084 | thd->lex->current_query_block()->max_equal_elems = | |
| 4244 | 822994 | std::max(thd->lex->current_query_block()->max_equal_elems, | |
| 4245 |
1/2✓ Branch 0 taken 822998 times.
✗ Branch 1 not taken.
|
823085 | item_equal->members()); |
| 4246 | 823024 | *retcond = item_equal; | |
| 4247 | 823024 | return false; | |
| 4248 | } | ||
| 4249 | |||
| 4250 | 20 | *retcond = eq_list.pop(); | |
| 4251 | ✗ | return false; | |
| 4252 | } else { | ||
| 4253 | /* | ||
| 4254 | Here a new AND level must be created. It can happen only | ||
| 4255 | when a row equality is processed as a standalone predicate. | ||
| 4256 | */ | ||
| 4257 |
2/4✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 68 times.
✗ Branch 3 not taken.
|
64 | Item_cond_and *and_cond = new Item_cond_and(eq_list); |
| 4258 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
|
68 | if (and_cond == nullptr) return true; |
| 4259 | |||
| 4260 | 68 | and_cond->quick_fix_field(); | |
| 4261 | 68 | List<Item> *args = and_cond->argument_list(); | |
| 4262 |
1/2✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
|
68 | List_iterator_fast<Item_equal> it(cond_equal.current_level); |
| 4263 |
2/2✓ Branch 0 taken 140 times.
✓ Branch 1 taken 68 times.
|
208 | while ((item_equal = it++)) { |
| 4264 |
2/4✓ Branch 0 taken 140 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 140 times.
|
140 | if (item_equal->resolve_type(thd)) return true; |
| 4265 |
1/2✓ Branch 0 taken 140 times.
✗ Branch 1 not taken.
|
140 | item_equal->update_used_tables(); |
| 4266 | 280 | thd->lex->current_query_block()->max_equal_elems = | |
| 4267 | 140 | std::max(thd->lex->current_query_block()->max_equal_elems, | |
| 4268 |
1/2✓ Branch 0 taken 140 times.
✗ Branch 1 not taken.
|
280 | item_equal->members()); |
| 4269 | } | ||
| 4270 |
1/2✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
|
68 | and_cond->cond_equal = cond_equal; |
| 4271 |
1/2✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
|
68 | args->concat((List<Item> *)&cond_equal.current_level); |
| 4272 | |||
| 4273 | 68 | *retcond = and_cond; | |
| 4274 | 68 | return false; | |
| 4275 | } | ||
| 4276 | } | ||
| 4277 | |||
| 4278 |
2/2✓ Branch 0 taken 1864389 times.
✓ Branch 1 taken 47 times.
|
1864436 | if (do_inherit) { |
| 4279 | /* | ||
| 4280 | For each field reference in cond, not from equal item predicates, | ||
| 4281 | set a pointer to the multiple equality it belongs to (if there is any) | ||
| 4282 | as soon the field is not of a string type or the field reference is | ||
| 4283 | an argument of a comparison predicate. | ||
| 4284 | */ | ||
| 4285 | 1864389 | uchar *is_subst_valid = (uchar *)1; | |
| 4286 |
1/2✓ Branch 0 taken 1864439 times.
✗ Branch 1 not taken.
|
1864389 | cond = cond->compile(&Item::subst_argument_checker, &is_subst_valid, |
| 4287 | &Item::equal_fields_propagator, (uchar *)inherited); | ||
| 4288 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1864439 times.
|
1864439 | if (cond == nullptr) return true; |
| 4289 | } | ||
| 4290 |
1/2✓ Branch 0 taken 1864430 times.
✗ Branch 1 not taken.
|
1864486 | cond->update_used_tables(); |
| 4291 | } | ||
| 4292 | 3713746 | *retcond = cond; | |
| 4293 | 3713746 | return false; | |
| 4294 | } | ||
| 4295 | |||
| 4296 | /** | ||
| 4297 | Build multiple equalities for a WHERE condition and all join conditions that | ||
| 4298 | inherit these multiple equalities. | ||
| 4299 | |||
| 4300 | The function first applies the build_equal_items_for_cond function | ||
| 4301 | to build all multiple equalities for condition cond utilizing equalities | ||
| 4302 | referred through the parameter inherited. The extended set of | ||
| 4303 | equalities is returned in the structure referred by the cond_equal_ref | ||
| 4304 | parameter. After this the function calls itself recursively for | ||
| 4305 | all join conditions whose direct references can be found in join_list | ||
| 4306 | and who inherit directly the multiple equalities just having built. | ||
| 4307 | |||
| 4308 | @note | ||
| 4309 | The join condition used in an outer join operation inherits all equalities | ||
| 4310 | from the join condition of the embedding join, if there is any, or | ||
| 4311 | otherwise - from the where condition. | ||
| 4312 | This fact is not obvious, but presumably can be proved. | ||
| 4313 | Consider the following query: | ||
| 4314 | @code | ||
| 4315 | SELECT * FROM (t1,t2) LEFT JOIN (t3,t4) ON t1.a=t3.a AND t2.a=t4.a | ||
| 4316 | WHERE t1.a=t2.a; | ||
| 4317 | @endcode | ||
| 4318 | If the join condition in the query inherits =(t1.a,t2.a), then we | ||
| 4319 | can build the multiple equality =(t1.a,t2.a,t3.a,t4.a) that infers | ||
| 4320 | the equality t3.a=t4.a. Although the join condition | ||
| 4321 | t1.a=t3.a AND t2.a=t4.a AND t3.a=t4.a is not equivalent to the one | ||
| 4322 | in the query the latter can be replaced by the former: the new query | ||
| 4323 | will return the same result set as the original one. | ||
| 4324 | |||
| 4325 | Interesting that multiple equality =(t1.a,t2.a,t3.a,t4.a) allows us | ||
| 4326 | to use t1.a=t3.a AND t3.a=t4.a under the join condition: | ||
| 4327 | @code | ||
| 4328 | SELECT * FROM (t1,t2) LEFT JOIN (t3,t4) ON t1.a=t3.a AND t3.a=t4.a | ||
| 4329 | WHERE t1.a=t2.a | ||
| 4330 | @endcode | ||
| 4331 | This query equivalent to: | ||
| 4332 | @code | ||
| 4333 | SELECT * FROM (t1 LEFT JOIN (t3,t4) ON t1.a=t3.a AND t3.a=t4.a),t2 | ||
| 4334 | WHERE t1.a=t2.a | ||
| 4335 | @endcode | ||
| 4336 | Similarly the original query can be rewritten to the query: | ||
| 4337 | @code | ||
| 4338 | SELECT * FROM (t1,t2) LEFT JOIN (t3,t4) ON t2.a=t4.a AND t3.a=t4.a | ||
| 4339 | WHERE t1.a=t2.a | ||
| 4340 | @endcode | ||
| 4341 | that is equivalent to: | ||
| 4342 | @code | ||
| 4343 | SELECT * FROM (t2 LEFT JOIN (t3,t4)ON t2.a=t4.a AND t3.a=t4.a), t1 | ||
| 4344 | WHERE t1.a=t2.a | ||
| 4345 | @endcode | ||
| 4346 | Thus, applying equalities from the where condition we basically | ||
| 4347 | can get more freedom in performing join operations. | ||
| 4348 | Although we don't use this property now, it probably makes sense to use | ||
| 4349 | it in the future. | ||
| 4350 | |||
| 4351 | @param thd Thread handler | ||
| 4352 | @param cond condition to build the multiple equalities for | ||
| 4353 | @param[out] retcond Returned condition | ||
| 4354 | @param inherited path to all inherited multiple equality items | ||
| 4355 | @param do_inherit whether or not to inherit equalities from other | ||
| 4356 | parts of the condition | ||
| 4357 | @param join_list list of join tables that the condition refers to | ||
| 4358 | @param[out] cond_equal_ref pointer to the structure to place built | ||
| 4359 | equalities in | ||
| 4360 | |||
| 4361 | @returns false if success, true if error | ||
| 4362 | */ | ||
| 4363 | |||
| 4364 | 2036821 | bool build_equal_items(THD *thd, Item *cond, Item **retcond, | |
| 4365 | COND_EQUAL *inherited, bool do_inherit, | ||
| 4366 | mem_root_deque<TABLE_LIST *> *join_list, | ||
| 4367 | COND_EQUAL **cond_equal_ref) { | ||
| 4368 | 2036821 | COND_EQUAL *cond_equal = nullptr; | |
| 4369 | |||
| 4370 |
2/2✓ Branch 0 taken 2031528 times.
✓ Branch 1 taken 5293 times.
|
2036821 | if (cond) { |
| 4371 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2031538 times.
|
2031528 | if (build_equal_items_for_cond(thd, cond, &cond, inherited, do_inherit)) |
| 4372 | 1 | return true; | |
| 4373 | 2031538 | cond->update_used_tables(); | |
| 4374 | // update_used_tables() returns void but can still fail. | ||
| 4375 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2031621 times.
|
2031617 | if (thd->is_error()) return true; |
| 4376 | |||
| 4377 | 2031621 | const enum Item::Type cond_type = cond->type(); | |
| 4378 |
4/4✓ Branch 0 taken 883574 times.
✓ Branch 1 taken 1147985 times.
✓ Branch 2 taken 860776 times.
✓ Branch 3 taken 1170800 times.
|
2915150 | if (cond_type == Item::COND_ITEM && |
| 4379 |
2/2✓ Branch 0 taken 860810 times.
✓ Branch 1 taken 22781 times.
|
883574 | down_cast<Item_cond *>(cond)->functype() == Item_func::COND_AND_FUNC) |
| 4380 | 860776 | cond_equal = &down_cast<Item_cond_and *>(cond)->cond_equal; | |
| 4381 |
4/4✓ Branch 0 taken 1147376 times.
✓ Branch 1 taken 23424 times.
✓ Branch 2 taken 810063 times.
✓ Branch 3 taken 360669 times.
|
2318108 | else if (cond_type == Item::FUNC_ITEM && |
| 4382 |
2/2✓ Branch 0 taken 810007 times.
✓ Branch 1 taken 337301 times.
|
1147376 | down_cast<Item_func *>(cond)->functype() == |
| 4383 | Item_func::MULT_EQUAL_FUNC) { | ||
| 4384 |
2/4✓ Branch 0 taken 810092 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 810101 times.
✗ Branch 3 not taken.
|
810063 | cond_equal = new (thd->mem_root) COND_EQUAL; |
| 4385 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 810101 times.
|
810101 | if (cond_equal == nullptr) return true; |
| 4386 | 810101 | cond_equal->current_level.push_back(down_cast<Item_equal *>(cond)); | |
| 4387 | } | ||
| 4388 | } | ||
| 4389 |
2/2✓ Branch 0 taken 1670882 times.
✓ Branch 1 taken 366105 times.
|
2036987 | if (cond_equal) { |
| 4390 | 1670882 | cond_equal->upper_levels = inherited; | |
| 4391 | 1670882 | inherited = cond_equal; | |
| 4392 | } | ||
| 4393 | 2036987 | *cond_equal_ref = cond_equal; | |
| 4394 | |||
| 4395 |
2/2✓ Branch 0 taken 1515060 times.
✓ Branch 1 taken 521927 times.
|
2036987 | if (join_list) { |
| 4396 |
7/12✓ Branch 0 taken 1515050 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1515062 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3569862 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3569852 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5084848 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3569834 times.
✓ Branch 11 taken 1515014 times.
|
5084877 | for (TABLE_LIST *table : *join_list) { |
| 4397 |
2/2✓ Branch 0 taken 525109 times.
✓ Branch 1 taken 3044711 times.
|
3569862 | if (table->join_cond_optim()) { |
| 4398 | 525109 | mem_root_deque<TABLE_LIST *> *nested_join_list = | |
| 4399 |
2/2✓ Branch 0 taken 3252 times.
✓ Branch 1 taken 521857 times.
|
525109 | table->nested_join ? &table->nested_join->join_list : nullptr; |
| 4400 | Item *join_cond; | ||
| 4401 |
2/4✓ Branch 0 taken 525100 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 525100 times.
|
525109 | if (build_equal_items(thd, table->join_cond_optim(), &join_cond, |
| 4402 | inherited, do_inherit, nested_join_list, | ||
| 4403 | &table->cond_equal)) | ||
| 4404 | ✗ | return true; | |
| 4405 | 525100 | table->set_join_cond_optim(join_cond); | |
| 4406 | } | ||
| 4407 | } | ||
| 4408 | } | ||
| 4409 | |||
| 4410 | 2036941 | *retcond = cond; | |
| 4411 | 2036941 | return false; | |
| 4412 | } | ||
| 4413 | |||
| 4414 | /** | ||
| 4415 | Compare field items by table order in the execution plan. | ||
| 4416 | |||
| 4417 | field1 considered as better than field2 if the table containing | ||
| 4418 | field1 is accessed earlier than the table containing field2. | ||
| 4419 | The function finds out what of two fields is better according | ||
| 4420 | this criteria. | ||
| 4421 | |||
| 4422 | @param field1 first field item to compare | ||
| 4423 | @param field2 second field item to compare | ||
| 4424 | @param table_join_idx index to tables determining table order | ||
| 4425 | |||
| 4426 | @retval | ||
| 4427 | -1 if field1 is better than field2 | ||
| 4428 | @retval | ||
| 4429 | 1 if field2 is better than field1 | ||
| 4430 | @retval | ||
| 4431 | 0 otherwise | ||
| 4432 | */ | ||
| 4433 | |||
| 4434 | 2589961 | static int compare_fields_by_table_order(Item_field *field1, Item_field *field2, | |
| 4435 | JOIN_TAB **table_join_idx) { | ||
| 4436 | 2589961 | int cmp = 0; | |
| 4437 | 2589961 | bool outer_ref = false; | |
| 4438 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2590056 times.
|
2589961 | if (field1->is_outer_reference()) { |
| 4439 | ✗ | outer_ref = true; | |
| 4440 | ✗ | cmp = -1; | |
| 4441 | } | ||
| 4442 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2590069 times.
|
2590056 | if (field2->is_outer_reference()) { |
| 4443 | ✗ | outer_ref = true; | |
| 4444 | ✗ | cmp++; | |
| 4445 | } | ||
| 4446 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2590069 times.
|
2590069 | if (outer_ref) return cmp; |
| 4447 | |||
| 4448 | /* | ||
| 4449 | table_join_idx is NULL if this function was not called from JOIN::optimize() | ||
| 4450 | but from e.g. mysql_delete() or mysql_update(). In these cases | ||
| 4451 | there is only one table and both fields belong to it. Example | ||
| 4452 | condition where this is the case: t1.fld1=t1.fld2 | ||
| 4453 | */ | ||
| 4454 |
2/2✓ Branch 0 taken 209 times.
✓ Branch 1 taken 2589860 times.
|
2590069 | if (!table_join_idx) return 0; |
| 4455 | |||
| 4456 | // Locate JOIN_TABs thanks to table_join_idx, then compare their index. | ||
| 4457 | 2589860 | cmp = table_join_idx[field1->table_ref->tableno()]->idx() - | |
| 4458 | 2589798 | table_join_idx[field2->table_ref->tableno()]->idx(); | |
| 4459 |
4/4✓ Branch 0 taken 1238298 times.
✓ Branch 1 taken 1351561 times.
✓ Branch 2 taken 1233331 times.
✓ Branch 3 taken 4967 times.
|
2589859 | return cmp < 0 ? -1 : (cmp ? 1 : 0); |
| 4460 | } | ||
| 4461 | |||
| 4462 | /** | ||
| 4463 | Generate minimal set of simple equalities equivalent to a multiple equality. | ||
| 4464 | |||
| 4465 | The function retrieves the fields of the multiple equality item | ||
| 4466 | item_equal and for each field f: | ||
| 4467 | - if item_equal contains const it generates the equality f=const_item; | ||
| 4468 | - otherwise, if f is not the first field, generates the equality | ||
| 4469 | f=item_equal->get_first(). | ||
| 4470 | All generated equality are added to the cond conjunction. | ||
| 4471 | |||
| 4472 | @param thd the session context | ||
| 4473 | @param cond condition to add the generated equality to | ||
| 4474 | @param upper_levels structure to access multiple equality of upper levels | ||
| 4475 | @param item_equal multiple equality to generate simple equality from | ||
| 4476 | |||
| 4477 | @note | ||
| 4478 | Before generating an equality function checks that it has not | ||
| 4479 | been generated for multiple equalities of the upper levels. | ||
| 4480 | E.g. for the following where condition | ||
| 4481 | WHERE a=5 AND ((a=b AND b=c) OR c>4) | ||
| 4482 | the upper level AND condition will contain =(5,a), | ||
| 4483 | while the lower level AND condition will contain =(5,a,b,c). | ||
| 4484 | When splitting =(5,a,b,c) into a separate equality predicates | ||
| 4485 | we should omit 5=a, as we have it already in the upper level. | ||
| 4486 | The following where condition gives us a more complicated case: | ||
| 4487 | WHERE t1.a=t2.b AND t3.c=t4.d AND (t2.b=t3.c OR t4.e>5 ...) AND ... | ||
| 4488 | Given the tables are accessed in the order t1->t2->t3->t4 for | ||
| 4489 | the selected query execution plan the lower level multiple | ||
| 4490 | equality =(t1.a,t2.b,t3.c,t4.d) formally should be converted to | ||
| 4491 | t1.a=t2.b AND t1.a=t3.c AND t1.a=t4.d. But t1.a=t2.a will be | ||
| 4492 | generated for the upper level. Also t3.c=t4.d will be generated there. | ||
| 4493 | So only t1.a=t3.c should be left in the lower level. | ||
| 4494 | If cond is equal to 0, then not more then one equality is generated | ||
| 4495 | and a pointer to it is returned as the result of the function. | ||
| 4496 | |||
| 4497 | @return | ||
| 4498 | - The condition with generated simple equalities or | ||
| 4499 | a pointer to the simple generated equality, if success. | ||
| 4500 | - 0, otherwise. | ||
| 4501 | */ | ||
| 4502 | |||
| 4503 | 4998995 | static Item *eliminate_item_equal(THD *thd, Item *cond, | |
| 4504 | COND_EQUAL *upper_levels, | ||
| 4505 | Item_equal *item_equal) { | ||
| 4506 | 4998995 | List<Item> eq_list; | |
| 4507 | 4999033 | Item *eq_item = nullptr; | |
| 4508 |
7/10✓ Branch 0 taken 4999055 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1644 times.
✓ Branch 3 taken 4997411 times.
✓ Branch 4 taken 1644 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1644 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1644 times.
✓ Branch 9 taken 4997411 times.
|
4999033 | if (((Item *)item_equal)->const_item() && !item_equal->val_int()) |
| 4509 |
1/2✓ Branch 0 taken 1644 times.
✗ Branch 1 not taken.
|
3288 | return new Item_func_false(); |
| 4510 | 4997411 | Item *const item_const = item_equal->get_const(); | |
| 4511 |
1/2✓ Branch 0 taken 4997340 times.
✗ Branch 1 not taken.
|
4997414 | auto it = item_equal->get_fields().begin(); |
| 4512 |
2/2✓ Branch 0 taken 1958196 times.
✓ Branch 1 taken 3039144 times.
|
4997340 | if (!item_const) { |
| 4513 | /* | ||
| 4514 | If there is a const item, match all field items with the const item, | ||
| 4515 | otherwise match the second and subsequent field items with the first one: | ||
| 4516 | */ | ||
| 4517 | 1958196 | it++; | |
| 4518 | } | ||
| 4519 |
4/6✓ Branch 0 taken 10087635 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10087612 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5090174 times.
✓ Branch 5 taken 4997438 times.
|
10087682 | while (it != item_equal->get_fields().end()) { |
| 4520 | /* | ||
| 4521 | Generate an equality of the form: | ||
| 4522 | item_field = some previous field in item_equal's list. | ||
| 4523 | |||
| 4524 | First see if we really need to generate it: | ||
| 4525 | */ | ||
| 4526 | 5090174 | Item_field *item_field = &*it++; // Field to generate equality for. | |
| 4527 |
1/2✓ Branch 0 taken 5090086 times.
✗ Branch 1 not taken.
|
5090101 | Item_equal *const upper = item_field->find_item_equal(upper_levels); |
| 4528 |
2/2✓ Branch 0 taken 157583 times.
✓ Branch 1 taken 4932503 times.
|
5090086 | if (upper) // item_field is in this upper equality |
| 4529 | { | ||
| 4530 |
6/6✓ Branch 0 taken 156675 times.
✓ Branch 1 taken 908 times.
✓ Branch 2 taken 156301 times.
✓ Branch 3 taken 372 times.
✓ Branch 4 taken 156306 times.
✓ Branch 5 taken 1275 times.
|
157583 | if (item_const && upper->get_const()) |
| 4531 | 156306 | continue; // Const at both levels, no need to generate at current level | |
| 4532 | /* | ||
| 4533 | If the upper-level multiple equality contains this item, there is no | ||
| 4534 | need to generate the equality, unless item_field belongs to a | ||
| 4535 | semi-join nest that is used for Materialization, and refers to tables | ||
| 4536 | that are outside of the materialized semi-join nest, | ||
| 4537 | As noted in Item_equal::get_subst_item(), subquery materialization | ||
| 4538 | does not have this problem. | ||
| 4539 | */ | ||
| 4540 | 1275 | JOIN_TAB *const tab = item_field->field->table->reginfo.join_tab; | |
| 4541 | |||
| 4542 |
6/8✓ Branch 0 taken 1292 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1292 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1167 times.
✓ Branch 5 taken 125 times.
✓ Branch 6 taken 1150 times.
✓ Branch 7 taken 125 times.
|
1275 | if (!(tab && sj_is_materialize_strategy(tab->get_sj_strategy()))) { |
| 4543 | Item_field *item_match; | ||
| 4544 |
1/2✓ Branch 0 taken 1150 times.
✗ Branch 1 not taken.
|
1150 | auto li = item_equal->get_fields().begin(); |
| 4545 |
2/2✓ Branch 0 taken 992 times.
✓ Branch 1 taken 158 times.
|
1150 | while ((item_match = &*li++) != item_field) { |
| 4546 |
2/4✓ Branch 0 taken 992 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 992 times.
✗ Branch 3 not taken.
|
992 | if (item_match->find_item_equal(upper_levels) == upper) |
| 4547 | 992 | break; // (item_match, item_field) is also in upper level equality | |
| 4548 | } | ||
| 4549 |
2/2✓ Branch 0 taken 992 times.
✓ Branch 1 taken 158 times.
|
1150 | if (item_match != item_field) continue; |
| 4550 | } | ||
| 4551 | } // ... if (upper). | ||
| 4552 | |||
| 4553 | /* | ||
| 4554 | item_field should be compared with the head of the multiple equality | ||
| 4555 | list. | ||
| 4556 | item_field may refer to a table that is within a semijoin materialization | ||
| 4557 | nest. In that case, the order of the join_tab entries may look like: | ||
| 4558 | |||
| 4559 | ot1 ot2 <subquery> ot5 SJM(it3 it4) | ||
| 4560 | |||
| 4561 | If we have a multiple equality | ||
| 4562 | |||
| 4563 | (ot1.c1, ot2.c2, <subquery>.c it3.c3, it4.c4, ot5.c5), | ||
| 4564 | |||
| 4565 | we should generate the following equalities: | ||
| 4566 | 1. ot1.c1 = ot2.c2 | ||
| 4567 | 2. ot1.c1 = <subquery>.c | ||
| 4568 | 3. it3.c3 = it4.c4 | ||
| 4569 | 4. ot1.c1 = ot5.c5 | ||
| 4570 | |||
| 4571 | Equalities 1) and 4) are regular equalities between two outer tables. | ||
| 4572 | Equality 2) is an equality that matches the outer query with a | ||
| 4573 | materialized temporary table. It is either performed as a lookup | ||
| 4574 | into the materialized table (SJM-lookup), or as a condition on the | ||
| 4575 | outer table (SJM-scan). | ||
| 4576 | Equality 3) is evaluated during semijoin materialization. | ||
| 4577 | |||
| 4578 | If there is a const item, match against this one. | ||
| 4579 | Otherwise, match against the first field item in the multiple equality, | ||
| 4580 | unless the item is within a materialized semijoin nest, in case it will | ||
| 4581 | be matched against the first item within the SJM nest. | ||
| 4582 | @see JOIN::set_prefix_tables() | ||
| 4583 | @see Item_equal::get_subst_item() | ||
| 4584 | */ | ||
| 4585 | |||
| 4586 | Item *const head = | ||
| 4587 |
3/4✓ Branch 0 taken 1990278 times.
✓ Branch 1 taken 2942508 times.
✓ Branch 2 taken 1990229 times.
✗ Branch 3 not taken.
|
4932786 | item_const ? item_const : item_equal->get_subst_item(item_field); |
| 4588 |
2/2✓ Branch 0 taken 3221 times.
✓ Branch 1 taken 4929516 times.
|
4932737 | if (head == item_field) continue; |
| 4589 | |||
| 4590 | // we have a pair, can generate 'item_field=head' | ||
| 4591 |
3/4✓ Branch 0 taken 32605 times.
✓ Branch 1 taken 4896911 times.
✓ Branch 2 taken 32605 times.
✗ Branch 3 not taken.
|
4929516 | if (eq_item) eq_list.push_back(eq_item); |
| 4592 | |||
| 4593 |
3/4✓ Branch 0 taken 4929619 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1987542 times.
✓ Branch 3 taken 2942077 times.
|
4929516 | if (head->type() == Item::FIELD_ITEM) { |
| 4594 | // Store away all fields that were considered equal, so that we are able | ||
| 4595 | // to undo this operation later if we have to. See | ||
| 4596 | // Item_func::ensure_multi_equality_fields_are_available for more details. | ||
| 4597 | 1987542 | Item_field *head_field = down_cast<Item_field *>(head); | |
| 4598 | 1987573 | head_field->set_item_equal_all_join_nests(item_equal); | |
| 4599 | } | ||
| 4600 |
2/4✓ Branch 0 taken 4929607 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4929638 times.
✗ Branch 3 not taken.
|
4929638 | eq_item = new Item_func_eq(item_field, head); |
| 4601 | |||
| 4602 |
6/8✓ Branch 0 taken 4929653 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4929690 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 4929674 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 4929674 times.
|
4929638 | if (!eq_item || down_cast<Item_func_eq *>(eq_item)->set_cmp_func()) |
| 4603 | 1 | return nullptr; | |
| 4604 | |||
| 4605 | 4929674 | eq_item->quick_fix_field(); | |
| 4606 |
2/2✓ Branch 0 taken 2942573 times.
✓ Branch 1 taken 1987058 times.
|
4929631 | if (item_const != nullptr) { |
| 4607 |
1/2✓ Branch 0 taken 2942599 times.
✗ Branch 1 not taken.
|
2942573 | eq_item->apply_is_true(); |
| 4608 | Item::cond_result res; | ||
| 4609 |
2/4✓ Branch 0 taken 2942777 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2942777 times.
|
2942599 | if (fold_condition(thd, eq_item, &eq_item, &res)) return nullptr; |
| 4610 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2942777 times.
|
2942777 | if (res == Item::COND_FALSE) { |
| 4611 | ✗ | eq_item = new (thd->mem_root) Item_func_false(); | |
| 4612 | ✗ | if (eq_item == nullptr) return nullptr; | |
| 4613 | ✗ | return eq_item; // entire AND is false | |
| 4614 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2942777 times.
|
2942777 | } else if (res == Item::COND_TRUE) { |
| 4615 | ✗ | eq_item = new (thd->mem_root) Item_func_true(); | |
| 4616 | ✗ | if (eq_item == nullptr) return nullptr; | |
| 4617 | } | ||
| 4618 | } | ||
| 4619 | } // ... while ((item_field= it++)) | ||
| 4620 | |||
| 4621 |
6/6✓ Branch 0 taken 825590 times.
✓ Branch 1 taken 4171848 times.
✓ Branch 2 taken 817903 times.
✓ Branch 3 taken 7637 times.
✓ Branch 4 taken 817913 times.
✓ Branch 5 taken 4179475 times.
|
4997438 | if (!cond && !eq_list.head()) { |
| 4622 |
3/4✓ Branch 0 taken 59308 times.
✓ Branch 1 taken 758605 times.
✓ Branch 2 taken 59308 times.
✗ Branch 3 not taken.
|
877221 | if (!eq_item) return new Item_func_true(); |
| 4623 | 758605 | return eq_item; | |
| 4624 | } | ||
| 4625 | |||
| 4626 |
3/4✓ Branch 0 taken 4138538 times.
✓ Branch 1 taken 40937 times.
✓ Branch 2 taken 4138538 times.
✗ Branch 3 not taken.
|
4179475 | if (eq_item) eq_list.push_back(eq_item); |
| 4627 |
2/2✓ Branch 0 taken 7634 times.
✓ Branch 1 taken 4171841 times.
|
4179475 | if (!cond) |
| 4628 |
2/4✓ Branch 0 taken 7634 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7634 times.
✗ Branch 3 not taken.
|
7634 | cond = new Item_cond_and(eq_list); |
| 4629 | else { | ||
| 4630 |
2/4✓ Branch 0 taken 4171841 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4171841 times.
|
4171841 | assert(cond->type() == Item::COND_ITEM); |
| 4631 |
3/4✓ Branch 0 taken 4130868 times.
✓ Branch 1 taken 40973 times.
✓ Branch 2 taken 4130896 times.
✗ Branch 3 not taken.
|
4171841 | if (eq_list.elements) ((Item_cond *)cond)->add_at_head(&eq_list); |
| 4632 | } | ||
| 4633 | |||
| 4634 | 4179503 | cond->quick_fix_field(); | |
| 4635 |
1/2✓ Branch 0 taken 4179534 times.
✗ Branch 1 not taken.
|
4179510 | cond->update_used_tables(); |
| 4636 | |||
| 4637 | 4179534 | return cond; | |
| 4638 | } | ||
| 4639 | |||
| 4640 | /** | ||
| 4641 | Substitute every field reference in a condition by the best equal field | ||
| 4642 | and eliminate all multiple equality predicates. | ||
| 4643 | |||
| 4644 | The function retrieves the cond condition and for each encountered | ||
| 4645 | multiple equality predicate it sorts the field references in it | ||
| 4646 | according to the order of tables specified by the table_join_idx | ||
| 4647 | parameter. Then it eliminates the multiple equality predicate by | ||
| 4648 | replacing it with the conjunction of simple equality predicates | ||
| 4649 | equating every field from the multiple equality to the first | ||
| 4650 | field in it, or to the constant, if there is any. | ||
| 4651 | After this, the function retrieves all other conjuncted | ||
| 4652 | predicates and substitutes every field reference by the field reference | ||
| 4653 | to the first equal field or equal constant if there are any. | ||
| 4654 | |||
| 4655 | @param thd the session context | ||
| 4656 | @param cond condition to process | ||
| 4657 | @param cond_equal multiple equalities to take into consideration | ||
| 4658 | @param table_join_idx index to tables determining field preference | ||
| 4659 | |||
| 4660 | @note | ||
| 4661 | At the first glance, a full sort of fields in multiple equality | ||
| 4662 | seems to be an overkill. Yet it's not the case due to possible | ||
| 4663 | new fields in multiple equality item of lower levels. We want | ||
| 4664 | the order in them to comply with the order of upper levels. | ||
| 4665 | |||
| 4666 | @return | ||
| 4667 | The transformed condition, or NULL in case of error | ||
| 4668 | */ | ||
| 4669 | |||
| 4670 | 4416713 | Item *substitute_for_best_equal_field(THD *thd, Item *cond, | |
| 4671 | COND_EQUAL *cond_equal, | ||
| 4672 | JOIN_TAB **table_join_idx) { | ||
| 4673 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4416840 times.
|
4416713 | assert(cond->is_bool_func()); |
| 4674 |
2/2✓ Branch 0 taken 1797156 times.
✓ Branch 1 taken 2619720 times.
|
4416840 | if (cond->type() == Item::COND_ITEM) { |
| 4675 | 1797156 | List<Item> *cond_list = ((Item_cond *)cond)->argument_list(); | |
| 4676 | |||
| 4677 | bool and_level = | ||
| 4678 |
1/2✓ Branch 0 taken 1797134 times.
✗ Branch 1 not taken.
|
1797131 | ((Item_cond *)cond)->functype() == Item_func::COND_AND_FUNC; |
| 4679 |
2/2✓ Branch 0 taken 1773473 times.
✓ Branch 1 taken 23661 times.
|
1797134 | if (and_level) { |
| 4680 | 1773473 | cond_equal = &((Item_cond_and *)cond)->cond_equal; | |
| 4681 | 1773473 | cond_list->disjoin((List<Item> *)&cond_equal->current_level); | |
| 4682 | |||
| 4683 |
1/2✓ Branch 0 taken 1773511 times.
✗ Branch 1 not taken.
|
1773494 | List_iterator_fast<Item_equal> it(cond_equal->current_level); |
| 4684 | 1749823 | auto cmp = [table_join_idx](Item_field *f1, Item_field *f2) { | |
| 4685 | 1749823 | return compare_fields_by_table_order(f1, f2, table_join_idx); | |
| 4686 | 1773511 | }; | |
| 4687 | Item_equal *item_equal; | ||
| 4688 |
2/2✓ Branch 0 taken 4173456 times.
✓ Branch 1 taken 1773524 times.
|
5946936 | while ((item_equal = it++)) { |
| 4689 |
1/2✓ Branch 0 taken 4173425 times.
✗ Branch 1 not taken.
|
4173456 | item_equal->sort(cmp); |
| 4690 | } | ||
| 4691 | } | ||
| 4692 | |||
| 4693 |
1/2✓ Branch 0 taken 1797165 times.
✗ Branch 1 not taken.
|
1797185 | List_iterator<Item> li(*cond_list); |
| 4694 | Item *item; | ||
| 4695 |
2/2✓ Branch 0 taken 2449075 times.
✓ Branch 1 taken 1797163 times.
|
4246214 | while ((item = li++)) { |
| 4696 |
1/2✓ Branch 0 taken 2449049 times.
✗ Branch 1 not taken.
|
2449075 | Item *new_item = substitute_for_best_equal_field(thd, item, cond_equal, |
| 4697 | table_join_idx); | ||
| 4698 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2449049 times.
|
2449049 | if (new_item == nullptr) return nullptr; |
| 4699 | /* | ||
| 4700 | This works OK with PS/SP re-execution as changes are made to | ||
| 4701 | the arguments of AND/OR items only | ||
| 4702 | */ | ||
| 4703 |
2/2✓ Branch 0 taken 12805 times.
✓ Branch 1 taken 2436244 times.
|
2449049 | if (new_item != item) li.replace(new_item); |
| 4704 | } | ||
| 4705 | |||
| 4706 |
2/2✓ Branch 0 taken 1773521 times.
✓ Branch 1 taken 23642 times.
|
1797163 | if (and_level) { |
| 4707 |
1/2✓ Branch 0 taken 1773521 times.
✗ Branch 1 not taken.
|
1773521 | List_iterator_fast<Item_equal> it(cond_equal->current_level); |
| 4708 | Item_equal *item_equal; | ||
| 4709 |
2/2✓ Branch 0 taken 4173451 times.
✓ Branch 1 taken 1771957 times.
|
5945421 | while ((item_equal = it++)) { |
| 4710 |
1/2✓ Branch 0 taken 4173455 times.
✗ Branch 1 not taken.
|
4173451 | cond = eliminate_item_equal(thd, cond, cond_equal->upper_levels, |
| 4711 | item_equal); | ||
| 4712 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4173455 times.
|
4173455 | if (cond == nullptr) return nullptr; |
| 4713 | // This occurs when eliminate_item_equal() founds that cond is | ||
| 4714 | // always false and substitutes it with a false value. | ||
| 4715 | // Due to this, value of item_equal will be 0, so just return it. | ||
| 4716 |
3/4✓ Branch 0 taken 4173463 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1563 times.
✓ Branch 3 taken 4171900 times.
|
4173455 | if (cond->type() != Item::COND_ITEM) break; |
| 4717 | } | ||
| 4718 | } | ||
| 4719 |
5/6✓ Branch 0 taken 1797166 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1795604 times.
✓ Branch 3 taken 1562 times.
✓ Branch 4 taken 15584 times.
✓ Branch 5 taken 1781580 times.
|
3592764 | if (cond->type() == Item::COND_ITEM && |
| 4720 |
2/2✓ Branch 0 taken 15584 times.
✓ Branch 1 taken 1780018 times.
|
1795604 | !((Item_cond *)cond)->argument_list()->elements) |
| 4721 |
3/6✓ Branch 0 taken 15584 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15584 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15584 times.
✗ Branch 5 not taken.
|
31168 | cond = cond->val_bool() ? implicit_cast<Item *>(new Item_func_true()) |
| 4722 | ✗ | : implicit_cast<Item *>(new Item_func_false()); | |
| 4723 |
4/4✓ Branch 0 taken 2619082 times.
✓ Branch 1 taken 502 times.
✓ Branch 2 taken 825629 times.
✓ Branch 3 taken 1794106 times.
|
5238953 | } else if (cond->type() == Item::FUNC_ITEM && |
| 4724 |
2/2✓ Branch 0 taken 825636 times.
✓ Branch 1 taken 1793597 times.
|
2619082 | (down_cast<Item_func *>(cond))->functype() == |
| 4725 | Item_func::MULT_EQUAL_FUNC) { | ||
| 4726 | 825629 | Item_equal *item_equal = down_cast<Item_equal *>(cond); | |
| 4727 | 825677 | item_equal->sort([table_join_idx](Item_field *f1, Item_field *f2) { | |
| 4728 | 840150 | return compare_fields_by_table_order(f1, f2, table_join_idx); | |
| 4729 | }); | ||
| 4730 |
6/6✓ Branch 0 taken 819507 times.
✓ Branch 1 taken 6042 times.
✓ Branch 2 taken 811786 times.
✓ Branch 3 taken 7788 times.
✓ Branch 4 taken 811758 times.
✓ Branch 5 taken 13858 times.
|
825549 | if (cond_equal && cond_equal->current_level.head() == item_equal) |
| 4731 | 811758 | cond_equal = cond_equal->upper_levels; | |
| 4732 | 825616 | return eliminate_item_equal(thd, nullptr, cond_equal, item_equal); | |
| 4733 | } else { | ||
| 4734 | 1794106 | uchar *dummy = nullptr; | |
| 4735 |
1/2✓ Branch 0 taken 1794106 times.
✗ Branch 1 not taken.
|
1794106 | if (cond->compile(&Item::visit_all_analyzer, &dummy, |
| 4736 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1794106 times.
|
1794106 | &Item::replace_equal_field, nullptr) == nullptr) |
| 4737 | ✗ | return nullptr; | |
| 4738 | } | ||
| 4739 | 3591270 | return cond; | |
| 4740 | } | ||
| 4741 | |||
| 4742 | /** | ||
| 4743 | change field = field to field = const for each found field = const in the | ||
| 4744 | and_level | ||
| 4745 | |||
| 4746 | @param thd Thread handler | ||
| 4747 | @param save_list saved list of COND_CMP | ||
| 4748 | @param and_father father of AND op | ||
| 4749 | @param cond Condition where fields are replaced with constant values | ||
| 4750 | @param field The field that will be substituted | ||
| 4751 | @param value The substitution value | ||
| 4752 | |||
| 4753 | @returns false if success, true if error | ||
| 4754 | */ | ||
| 4755 | |||
| 4756 | 500560 | static bool change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list, | |
| 4757 | Item *and_father, Item *cond, Item *field, | ||
| 4758 | Item *value) { | ||
| 4759 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 500560 times.
|
500560 | assert(cond->real_item()->is_bool_func()); |
| 4760 |
2/2✓ Branch 0 taken 134564 times.
✓ Branch 1 taken 365996 times.
|
500560 | if (cond->type() == Item::COND_ITEM) { |
| 4761 | 134564 | Item_cond *const item_cond = down_cast<Item_cond *>(cond); | |
| 4762 |
1/2✓ Branch 0 taken 134564 times.
✗ Branch 1 not taken.
|
134564 | bool and_level = item_cond->functype() == Item_func::COND_AND_FUNC; |
| 4763 |
1/2✓ Branch 0 taken 134564 times.
✗ Branch 1 not taken.
|
134564 | List_iterator<Item> li(*item_cond->argument_list()); |
| 4764 | Item *item; | ||
| 4765 |
2/2✓ Branch 0 taken 366497 times.
✓ Branch 1 taken 134564 times.
|
501061 | while ((item = li++)) { |
| 4766 |
4/6✓ Branch 0 taken 365507 times.
✓ Branch 1 taken 990 times.
✓ Branch 2 taken 366497 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 366497 times.
|
366497 | if (change_cond_ref_to_const(thd, save_list, and_level ? cond : item, |
| 4767 | item, field, value)) | ||
| 4768 | ✗ | return true; | |
| 4769 | } | ||
| 4770 | 134564 | return false; | |
| 4771 | } | ||
| 4772 |
2/2✓ Branch 0 taken 126969 times.
✓ Branch 1 taken 239027 times.
|
365996 | if (cond->eq_cmp_result() == Item::COND_OK) |
| 4773 | 126969 | return false; // Not a boolean function | |
| 4774 | |||
| 4775 | 239027 | Item_bool_func2 *func = down_cast<Item_bool_func2 *>(cond); | |
| 4776 | 239027 | Item **args = func->arguments(); | |
| 4777 | 239027 | Item *left_item = args[0]; | |
| 4778 | 239027 | Item *right_item = args[1]; | |
| 4779 | 239027 | Item_func::Functype functype = func->functype(); | |
| 4780 | |||
| 4781 |
2/2✓ Branch 0 taken 110 times.
✓ Branch 1 taken 232 times.
|
239369 | if (right_item->eq(field, false) && left_item != value && |
| 4782 |
5/6✓ Branch 0 taken 342 times.
✓ Branch 1 taken 238685 times.
✓ Branch 2 taken 110 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 110 times.
✓ Branch 5 taken 238917 times.
|
239479 | right_item->cmp_context == field->cmp_context && |
| 4783 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 95 times.
|
110 | (left_item->result_type() != STRING_RESULT || |
| 4784 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | value->result_type() != STRING_RESULT || |
| 4785 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | left_item->collation.collation == value->collation.collation)) { |
| 4786 | 110 | Item *const clone = value->clone_item(); | |
| 4787 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
|
110 | if (thd->is_error()) return true; |
| 4788 | |||
| 4789 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 84 times.
|
110 | if (clone == nullptr) return false; |
| 4790 | |||
| 4791 | 84 | clone->collation.set(right_item->collation); | |
| 4792 | 84 | thd->change_item_tree(args + 1, clone); | |
| 4793 | 84 | func->update_used_tables(); | |
| 4794 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 47 times.
✓ Branch 3 taken 27 times.
|
84 | if ((functype == Item_func::EQ_FUNC || functype == Item_func::EQUAL_FUNC) && |
| 4795 |
6/6✓ Branch 0 taken 10 times.
✓ Branch 1 taken 74 times.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 44 times.
✓ Branch 5 taken 40 times.
|
168 | and_father != cond && !left_item->const_item()) { |
| 4796 | 44 | cond->marker = Item::MARKER_CONST_PROPAG; | |
| 4797 |
1/2✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
|
44 | COND_CMP *const cond_cmp = new COND_CMP(and_father, func); |
| 4798 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | if (cond_cmp == nullptr) return true; |
| 4799 | |||
| 4800 | 44 | save_list->push_back(cond_cmp); | |
| 4801 | } | ||
| 4802 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
|
84 | if (func->set_cmp_func()) return true; |
| 4803 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 133746 times.
|
372698 | } else if (left_item->eq(field, false) && right_item != value && |
| 4804 |
5/6✓ Branch 0 taken 133781 times.
✓ Branch 1 taken 105136 times.
✓ Branch 2 taken 35 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 238883 times.
|
372733 | left_item->cmp_context == field->cmp_context && |
| 4805 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 9 times.
|
35 | (right_item->result_type() != STRING_RESULT || |
| 4806 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | value->result_type() != STRING_RESULT || |
| 4807 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 1 times.
|
26 | right_item->collation.collation == value->collation.collation)) { |
| 4808 | 34 | Item *const clone = value->clone_item(); | |
| 4809 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (thd->is_error()) return true; |
| 4810 | |||
| 4811 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (clone == nullptr) return false; |
| 4812 | |||
| 4813 | 34 | clone->collation.set(left_item->collation); | |
| 4814 | 34 | thd->change_item_tree(args, clone); | |
| 4815 | 34 | value = clone; | |
| 4816 | 34 | func->update_used_tables(); | |
| 4817 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
34 | if ((functype == Item_func::EQ_FUNC || functype == Item_func::EQUAL_FUNC) && |
| 4818 |
6/6✓ Branch 0 taken 21 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 26 times.
|
68 | and_father != cond && !right_item->const_item()) { |
| 4819 | 8 | args[0] = args[1]; // For easy check | |
| 4820 | 8 | thd->change_item_tree(args + 1, value); | |
| 4821 | 8 | cond->marker = Item::MARKER_CONST_PROPAG; | |
| 4822 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | COND_CMP *const cond_cmp = new COND_CMP(and_father, func); |
| 4823 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (cond_cmp == nullptr) return true; |
| 4824 | |||
| 4825 | 8 | save_list->push_back(cond_cmp); | |
| 4826 | } | ||
| 4827 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (func->set_cmp_func()) return true; |
| 4828 | } | ||
| 4829 | 239001 | return false; | |
| 4830 | } | ||
| 4831 | |||
| 4832 | /** | ||
| 4833 | Propagate constant values in a condition | ||
| 4834 | |||
| 4835 | @param thd Thread handler | ||
| 4836 | @param save_list saved list of COND_CMP | ||
| 4837 | @param and_father father of AND op | ||
| 4838 | @param cond Condition for which constant values are propagated | ||
| 4839 | |||
| 4840 | @returns false if success, true if error | ||
| 4841 | */ | ||
| 4842 | 7923404 | static bool propagate_cond_constants(THD *thd, I_List<COND_CMP> *save_list, | |
| 4843 | Item *and_father, Item *cond) { | ||
| 4844 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7923464 times.
|
7923404 | assert(cond->real_item()->is_bool_func()); |
| 4845 |
2/2✓ Branch 0 taken 1694712 times.
✓ Branch 1 taken 6228795 times.
|
7923464 | if (cond->type() == Item::COND_ITEM) { |
| 4846 | 1694712 | Item_cond *const item_cond = down_cast<Item_cond *>(cond); | |
| 4847 |
1/2✓ Branch 0 taken 1694597 times.
✗ Branch 1 not taken.
|
1694609 | bool and_level = item_cond->functype() == Item_func::COND_AND_FUNC; |
| 4848 |
1/2✓ Branch 0 taken 1694608 times.
✗ Branch 1 not taken.
|
1694597 | List_iterator_fast<Item> li(*item_cond->argument_list()); |
| 4849 | Item *item; | ||
| 4850 |
1/2✓ Branch 0 taken 1694567 times.
✗ Branch 1 not taken.
|
1694608 | I_List<COND_CMP> save; |
| 4851 |
2/2✓ Branch 0 taken 6406818 times.
✓ Branch 1 taken 1694592 times.
|
8101385 | while ((item = li++)) { |
| 4852 |
5/6✓ Branch 0 taken 5378512 times.
✓ Branch 1 taken 1028306 times.
✓ Branch 2 taken 6406819 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 6406818 times.
|
6406818 | if (propagate_cond_constants(thd, &save, and_level ? cond : item, item)) |
| 4853 | 1 | return true; | |
| 4854 | } | ||
| 4855 |
2/2✓ Branch 0 taken 1663620 times.
✓ Branch 1 taken 30972 times.
|
1694592 | if (and_level) { // Handle other found items |
| 4856 |
1/2✓ Branch 0 taken 1663623 times.
✗ Branch 1 not taken.
|
1663620 | I_List_iterator<COND_CMP> cond_itr(save); |
| 4857 | COND_CMP *cond_cmp; | ||
| 4858 |
3/4✓ Branch 0 taken 1663669 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
✓ Branch 3 taken 1663617 times.
|
1663675 | while ((cond_cmp = cond_itr++)) { |
| 4859 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | Item **args = cond_cmp->cmp_func->arguments(); |
| 4860 |
3/6✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 52 times.
|
104 | if (!args[0]->const_item() && |
| 4861 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | change_cond_ref_to_const(thd, &save, cond_cmp->and_level, |
| 4862 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | cond_cmp->and_level, args[0], args[1])) |
| 4863 | ✗ | return true; | |
| 4864 | } | ||
| 4865 | } | ||
| 4866 |
2/2✓ Branch 0 taken 5370237 times.
✓ Branch 1 taken 858558 times.
|
6228795 | } else if (and_father != cond && |
| 4867 |
2/2✓ Branch 0 taken 5370215 times.
✓ Branch 1 taken 22 times.
|
5370237 | cond->marker != Item::MARKER_CONST_PROPAG) // In a AND group |
| 4868 | { | ||
| 4869 | Item_func *func; | ||
| 4870 |
1/2✓ Branch 0 taken 5369938 times.
✗ Branch 1 not taken.
|
10740145 | if (cond->type() == Item::FUNC_ITEM && |
| 4871 |
4/4✓ Branch 0 taken 5369899 times.
✓ Branch 1 taken 322 times.
✓ Branch 2 taken 173296 times.
✓ Branch 3 taken 5196947 times.
|
10740142 | (func = down_cast<Item_func *>(cond)) && |
| 4872 |
2/2✓ Branch 0 taken 5196772 times.
✓ Branch 1 taken 173146 times.
|
5369938 | (func->functype() == Item_func::EQ_FUNC || |
| 4873 |
2/2✓ Branch 0 taken 150 times.
✓ Branch 1 taken 5196633 times.
|
5196772 | func->functype() == Item_func::EQUAL_FUNC)) { |
| 4874 | 173296 | Item **args = func->arguments(); | |
| 4875 | 173296 | bool left_const = args[0]->const_item(); | |
| 4876 | 173296 | bool right_const = args[1]->const_item(); | |
| 4877 |
6/6✓ Branch 0 taken 625 times.
✓ Branch 1 taken 172671 times.
✓ Branch 2 taken 248 times.
✓ Branch 3 taken 377 times.
✓ Branch 4 taken 167109 times.
✓ Branch 5 taken 6187 times.
|
346215 | if (!(left_const && right_const) && |
| 4878 |
2/2✓ Branch 0 taken 167109 times.
✓ Branch 1 taken 5810 times.
|
172919 | args[0]->result_type() == args[1]->result_type()) { |
| 4879 |
2/2✓ Branch 0 taken 133768 times.
✓ Branch 1 taken 33341 times.
|
167109 | if (right_const) { |
| 4880 | 133768 | Item *item = args[1]; | |
| 4881 |
3/4✓ Branch 0 taken 133768 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 133767 times.
|
133768 | if (resolve_const_item(thd, &item, args[0])) return true; |
| 4882 |
1/2✓ Branch 0 taken 133767 times.
✗ Branch 1 not taken.
|
133767 | thd->change_item_tree(&args[1], item); |
| 4883 |
1/2✓ Branch 0 taken 133767 times.
✗ Branch 1 not taken.
|
133767 | func->update_used_tables(); |
| 4884 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 133767 times.
|
133767 | if (change_cond_ref_to_const(thd, save_list, and_father, and_father, |
| 4885 |
1/2✓ Branch 0 taken 133767 times.
✗ Branch 1 not taken.
|
133767 | args[0], args[1])) |
| 4886 | ✗ | return true; | |
| 4887 |
2/2✓ Branch 0 taken 244 times.
✓ Branch 1 taken 33097 times.
|
33341 | } else if (left_const) { |
| 4888 | 244 | Item *item = args[0]; | |
| 4889 |
2/4✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 244 times.
|
244 | if (resolve_const_item(thd, &item, args[1])) return true; |
| 4890 |
1/2✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
|
244 | thd->change_item_tree(&args[0], item); |
| 4891 |
1/2✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
|
244 | func->update_used_tables(); |
| 4892 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
|
244 | if (change_cond_ref_to_const(thd, save_list, and_father, and_father, |
| 4893 |
1/2✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
|
244 | args[1], args[0])) |
| 4894 | ✗ | return true; | |
| 4895 | } | ||
| 4896 | } | ||
| 4897 | } | ||
| 4898 | } | ||
| 4899 | |||
| 4900 | 7923411 | return false; | |
| 4901 | } | ||
| 4902 | |||
| 4903 | /** | ||
| 4904 | Assign each nested join structure a bit in nested_join_map. | ||
| 4905 | |||
| 4906 | @param join_list List of tables | ||
| 4907 | @param first_unused Number of first unused bit in nested_join_map before the | ||
| 4908 | call | ||
| 4909 | |||
| 4910 | @note | ||
| 4911 | This function is called after simplify_joins(), when there are no | ||
| 4912 | redundant nested joins. | ||
| 4913 | We cannot have more nested joins in a query block than there are tables, | ||
| 4914 | so as long as the number of bits in nested_join_map is not less than the | ||
| 4915 | maximum number of tables in a query block, nested_join_map can never | ||
| 4916 | overflow. | ||
| 4917 | |||
| 4918 | @return | ||
| 4919 | First unused bit in nested_join_map after the call. | ||
| 4920 | */ | ||
| 4921 | |||
| 4922 | 13809526 | uint build_bitmap_for_nested_joins(mem_root_deque<TABLE_LIST *> *join_list, | |
| 4923 | uint first_unused) { | ||
| 4924 |
1/2✓ Branch 0 taken 13810241 times.
✗ Branch 1 not taken.
|
13809526 | DBUG_TRACE; |
| 4925 |
7/12✓ Branch 0 taken 13810218 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13810232 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3729363 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3729364 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 17539076 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3729357 times.
✓ Branch 11 taken 13809719 times.
|
17539604 | for (TABLE_LIST *table : *join_list) { |
| 4926 | NESTED_JOIN *nested_join; | ||
| 4927 |
2/2✓ Branch 0 taken 24689 times.
✓ Branch 1 taken 3704674 times.
|
3729363 | if ((nested_join = table->nested_join)) { |
| 4928 | // We should have a join condition or a semi-join condition or both | ||
| 4929 |
3/4✓ Branch 0 taken 21347 times.
✓ Branch 1 taken 3342 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21347 times.
|
24689 | assert((table->join_cond() != nullptr) || table->is_sj_nest()); |
| 4930 | |||
| 4931 | 24689 | nested_join->nj_map = 0; | |
| 4932 | 24689 | nested_join->nj_total = 0; | |
| 4933 | /* | ||
| 4934 | We only record nested join information for outer join nests. | ||
| 4935 | Tables belonging in semi-join nests are recorded in the | ||
| 4936 | embedding outer join nest, if one exists. | ||
| 4937 | */ | ||
| 4938 |
2/2✓ Branch 0 taken 3342 times.
✓ Branch 1 taken 21347 times.
|
24689 | if (table->join_cond()) { |
| 4939 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3342 times.
|
3342 | assert(first_unused < sizeof(nested_join_map) * 8); |
| 4940 | 3342 | nested_join->nj_map = (nested_join_map)1 << first_unused++; | |
| 4941 | 3342 | nested_join->nj_total = nested_join->join_list.size(); | |
| 4942 |
1/2✓ Branch 0 taken 21347 times.
✗ Branch 1 not taken.
|
21347 | } else if (table->is_sj_nest()) { |
| 4943 | 21347 | NESTED_JOIN *const outer_nest = | |
| 4944 |
2/2✓ Branch 0 taken 890 times.
✓ Branch 1 taken 20457 times.
|
21347 | table->embedding ? table->embedding->nested_join : nullptr; |
| 4945 | /* | ||
| 4946 | The semi-join nest has already been counted into the table count | ||
| 4947 | for the outer join nest as one table, so subtract 1 from the | ||
| 4948 | table count. | ||
| 4949 | */ | ||
| 4950 |
2/2✓ Branch 0 taken 890 times.
✓ Branch 1 taken 20457 times.
|
21347 | if (outer_nest) |
| 4951 | 890 | outer_nest->nj_total += (nested_join->join_list.size() - 1); | |
| 4952 | } else | ||
| 4953 | ✗ | assert(false); | |
| 4954 | |||
| 4955 | first_unused = | ||
| 4956 |
1/2✓ Branch 0 taken 24689 times.
✗ Branch 1 not taken.
|
24689 | build_bitmap_for_nested_joins(&nested_join->join_list, first_unused); |
| 4957 | } | ||
| 4958 | } | ||
| 4959 | 13810258 | return first_unused; | |
| 4960 | 13809719 | } | |
| 4961 | |||
| 4962 | /** Update the dependency map for the tables. */ | ||
| 4963 | |||
| 4964 | 1816574 | void JOIN::update_depend_map() { | |
| 4965 |
3/6✓ Branch 0 taken 1816593 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1816597 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1816626 times.
✗ Branch 5 not taken.
|
1816574 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 4966 |
2/2✓ Branch 0 taken 6257593 times.
✓ Branch 1 taken 1816670 times.
|
8074263 | for (uint tableno = 0; tableno < tables; tableno++) { |
| 4967 | 6257593 | JOIN_TAB *const tab = best_ref[tableno]; | |
| 4968 | 6257593 | TABLE_REF *const ref = &tab->ref(); | |
| 4969 | 6257627 | table_map depend_map = 0; | |
| 4970 | 6257627 | Item **item = ref->items; | |
| 4971 |
2/2✓ Branch 0 taken 2457922 times.
✓ Branch 1 taken 6257651 times.
|
8715573 | for (uint i = 0; i < ref->key_parts; i++, item++) |
| 4972 | 2457922 | depend_map |= (*item)->used_tables(); | |
| 4973 | 6257651 | depend_map &= ~PSEUDO_TABLE_BITS; | |
| 4974 | 6257651 | ref->depend_map = depend_map; | |
| 4975 |
2/2✓ Branch 0 taken 3807824 times.
✓ Branch 1 taken 6257656 times.
|
10065480 | for (JOIN_TAB **tab2 = map2table; depend_map; tab2++, depend_map >>= 1) { |
| 4976 |
2/2✓ Branch 0 taken 1845456 times.
✓ Branch 1 taken 1962368 times.
|
3807824 | if (depend_map & 1) ref->depend_map |= (*tab2)->ref().depend_map; |
| 4977 | } | ||
| 4978 | } | ||
| 4979 | 1816670 | } | |
| 4980 | |||
| 4981 | /** Update the dependency map for the sort order. */ | ||
| 4982 | |||
| 4983 | 3464417 | void JOIN::update_depend_map(ORDER *order) { | |
| 4984 |
1/2✓ Branch 0 taken 3464465 times.
✗ Branch 1 not taken.
|
3464417 | DBUG_TRACE; |
| 4985 |
2/2✓ Branch 0 taken 893923 times.
✓ Branch 1 taken 3464465 times.
|
4358388 | for (; order; order = order->next) { |
| 4986 | table_map depend_map; | ||
| 4987 |
1/2✓ Branch 0 taken 893923 times.
✗ Branch 1 not taken.
|
893923 | order->item[0]->update_used_tables(); |
| 4988 | 893923 | order->depend_map = depend_map = | |
| 4989 |
1/2✓ Branch 0 taken 893923 times.
✗ Branch 1 not taken.
|
893923 | order->item[0]->used_tables() & ~INNER_TABLE_BIT; |
| 4990 | 893923 | order->used = 0; | |
| 4991 | // Not item_sum(), RAND() and no reference to table outside of sub select | ||
| 4992 |
4/4✓ Branch 0 taken 893567 times.
✓ Branch 1 taken 356 times.
✓ Branch 2 taken 893222 times.
✓ Branch 3 taken 701 times.
|
1787490 | if (!(order->depend_map & (OUTER_REF_TABLE_BIT | RAND_TABLE_BIT)) && |
| 4993 |
2/2✓ Branch 0 taken 893222 times.
✓ Branch 1 taken 345 times.
|
893567 | !order->item[0]->has_aggregation()) { |
| 4994 |
2/2✓ Branch 0 taken 1182320 times.
✓ Branch 1 taken 893222 times.
|
2075542 | for (JOIN_TAB **tab = map2table; depend_map; tab++, depend_map >>= 1) { |
| 4995 |
2/2✓ Branch 0 taken 944686 times.
✓ Branch 1 taken 237634 times.
|
1182320 | if (depend_map & 1) order->depend_map |= (*tab)->ref().depend_map; |
| 4996 | } | ||
| 4997 | } | ||
| 4998 | } | ||
| 4999 | 3464465 | } | |
| 5000 | |||
| 5001 | /** | ||
| 5002 | Update equalities and keyuse references after semi-join materialization | ||
| 5003 | strategy is chosen. | ||
| 5004 | |||
| 5005 | @details | ||
| 5006 | For each multiple equality that contains a field that is selected | ||
| 5007 | from a subquery, and that subquery is executed using a semi-join | ||
| 5008 | materialization strategy, add the corresponding column in the materialized | ||
| 5009 | temporary table to the equality. | ||
| 5010 | For each injected semi-join equality that is not converted to | ||
| 5011 | multiple equality, replace the reference to the expression selected | ||
| 5012 | from the subquery with the corresponding column in the temporary table. | ||
| 5013 | |||
| 5014 | This is needed to properly reflect the equalities that involve injected | ||
| 5015 | semi-join equalities when materialization strategy is chosen. | ||
| 5016 | @see eliminate_item_equal() for how these equalities are used to generate | ||
| 5017 | correct equality predicates. | ||
| 5018 | |||
| 5019 | The MaterializeScan semi-join strategy requires some additional processing: | ||
| 5020 | All primary tables after the materialized temporary table must be inspected | ||
| 5021 | for keyuse objects that point to expressions from the subquery tables. | ||
| 5022 | These references must be replaced with references to corresponding columns | ||
| 5023 | in the materialized temporary table instead. Those primary tables using | ||
| 5024 | ref access will thus be made to depend on the materialized temporary table | ||
| 5025 | instead of the subquery tables. | ||
| 5026 | |||
| 5027 | Only the injected semi-join equalities need this treatment, other predicates | ||
| 5028 | will be handled correctly by the regular item substitution process. | ||
| 5029 | |||
| 5030 | @return False if success, true if error | ||
| 5031 | */ | ||
| 5032 | |||
| 5033 | 19226 | bool JOIN::update_equalities_for_sjm() { | |
| 5034 |
3/6✓ Branch 0 taken 19226 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19226 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19226 times.
✗ Branch 5 not taken.
|
19226 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 5035 |
1/2✓ Branch 0 taken 19226 times.
✗ Branch 1 not taken.
|
19226 | List_iterator<Semijoin_mat_exec> sj_it(sjm_exec_list); |
| 5036 | Semijoin_mat_exec *sjm_exec; | ||
| 5037 |
2/2✓ Branch 0 taken 4591 times.
✓ Branch 1 taken 19226 times.
|
23817 | while ((sjm_exec = sj_it++)) { |
| 5038 | 4591 | TABLE_LIST *const sj_nest = sjm_exec->sj_nest; | |
| 5039 | |||
| 5040 | Item *cond; | ||
| 5041 | /* | ||
| 5042 | Conditions involving SJ-inner tables are only to be found in the closest | ||
| 5043 | nest's condition, which may be an AJ nest, a LEFT JOIN nest, or the | ||
| 5044 | WHERE clause. | ||
| 5045 | */ | ||
| 5046 |
2/2✓ Branch 0 taken 53 times.
✓ Branch 1 taken 4538 times.
|
4591 | if (sj_nest->is_aj_nest()) |
| 5047 | 53 | cond = sj_nest->join_cond_optim(); | |
| 5048 |
2/2✓ Branch 0 taken 275 times.
✓ Branch 1 taken 4263 times.
|
4538 | else if (sj_nest->outer_join_nest()) |
| 5049 | 275 | cond = sj_nest->outer_join_nest()->join_cond_optim(); | |
| 5050 | else | ||
| 5051 | 4263 | cond = where_cond; | |
| 5052 |
2/2✓ Branch 0 taken 49 times.
✓ Branch 1 taken 4542 times.
|
4591 | if (!cond) continue; |
| 5053 | |||
| 5054 | 4542 | uchar *dummy = nullptr; | |
| 5055 |
1/2✓ Branch 0 taken 4542 times.
✗ Branch 1 not taken.
|
4542 | cond = cond->compile(&Item::equality_substitution_analyzer, &dummy, |
| 5056 | &Item::equality_substitution_transformer, | ||
| 5057 | (uchar *)sj_nest); | ||
| 5058 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4542 times.
|
4542 | if (cond == nullptr) return true; |
| 5059 | |||
| 5060 |
1/2✓ Branch 0 taken 4542 times.
✗ Branch 1 not taken.
|
4542 | cond->update_used_tables(); |
| 5061 | |||
| 5062 | // Loop over all primary tables that follow the materialized table | ||
| 5063 |
2/2✓ Branch 0 taken 3243 times.
✓ Branch 1 taken 4542 times.
|
7785 | for (uint j = sjm_exec->mat_table_index + 1; j < primary_tables; j++) { |
| 5064 | 3243 | JOIN_TAB *const tab = best_ref[j]; | |
| 5065 | 4748 | for (Key_use *keyuse = tab->position()->key; | |
| 5066 |
6/6✓ Branch 0 taken 2902 times.
✓ Branch 1 taken 1846 times.
✓ Branch 2 taken 1535 times.
✓ Branch 3 taken 1367 times.
✓ Branch 4 taken 1505 times.
✓ Branch 5 taken 3243 times.
|
6283 | keyuse && keyuse->table_ref == tab->table_ref && |
| 5067 |
2/2✓ Branch 0 taken 1505 times.
✓ Branch 1 taken 30 times.
|
1535 | keyuse->key == tab->position()->key->key; |
| 5068 | keyuse++) { | ||
| 5069 | 1505 | uint fieldno = 0; | |
| 5070 |
6/10✓ Branch 0 taken 1505 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1505 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1568 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1999 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1568 times.
✓ Branch 9 taken 431 times.
|
1999 | for (Item *old : sj_nest->nested_join->sj_inner_exprs) { |
| 5071 |
5/8✓ Branch 0 taken 1568 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1568 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1568 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1074 times.
✓ Branch 7 taken 494 times.
|
1568 | if (old->real_item()->eq(keyuse->val->real_item(), false)) { |
| 5072 | /* | ||
| 5073 | Replace the expression selected from the subquery with the | ||
| 5074 | corresponding column of the materialized temporary table. | ||
| 5075 | */ | ||
| 5076 | 1074 | keyuse->val = sj_nest->nested_join->sjm.mat_fields[fieldno]; | |
| 5077 |
1/2✓ Branch 0 taken 1074 times.
✗ Branch 1 not taken.
|
1074 | keyuse->used_tables = keyuse->val->used_tables(); |
| 5078 | 1074 | break; | |
| 5079 | } | ||
| 5080 |
1/2✓ Branch 0 taken 494 times.
✗ Branch 1 not taken.
|
494 | fieldno++; |
| 5081 | } | ||
| 5082 | } | ||
| 5083 | } | ||
| 5084 | } | ||
| 5085 | |||
| 5086 | 19226 | return false; | |
| 5087 | } | ||
| 5088 | |||
| 5089 | /** | ||
| 5090 | Assign set of available (prefix) tables to all tables in query block. | ||
| 5091 | Also set added tables, ie the tables added in each JOIN_TAB compared to the | ||
| 5092 | previous JOIN_TAB. | ||
| 5093 | This function must be called for every query block after the table order | ||
| 5094 | has been determined. | ||
| 5095 | */ | ||
| 5096 | |||
| 5097 | 1767388 | void JOIN::set_prefix_tables() { | |
| 5098 |
3/6✓ Branch 0 taken 1767402 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1767427 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1767452 times.
✗ Branch 5 not taken.
|
1767388 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 5099 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1767455 times.
|
1767438 | assert(!plan_is_const()); |
| 5100 | /* | ||
| 5101 | The const tables are available together with the first non-const table in | ||
| 5102 | the join order. | ||
| 5103 | */ | ||
| 5104 | 1767455 | table_map const initial_tables_map = | |
| 5105 |
2/2✓ Branch 0 taken 1765355 times.
✓ Branch 1 taken 2100 times.
|
1767455 | const_table_map | (allow_outer_refs ? OUTER_REF_TABLE_BIT : 0); |
| 5106 | |||
| 5107 | 1767455 | table_map current_tables_map = initial_tables_map; | |
| 5108 | 1767455 | table_map prev_tables_map = (table_map)0; | |
| 5109 | 1767455 | table_map saved_tables_map = (table_map)0; | |
| 5110 | |||
| 5111 | 1767455 | JOIN_TAB *last_non_sjm_tab = nullptr; // Track the last non-sjm table | |
| 5112 | |||
| 5113 |
2/2✓ Branch 0 taken 6150689 times.
✓ Branch 1 taken 1767511 times.
|
7918200 | for (uint i = const_tables; i < tables; i++) { |
| 5114 | 6150689 | JOIN_TAB *const tab = best_ref[i]; | |
| 5115 |
2/2✓ Branch 0 taken 2335355 times.
✓ Branch 1 taken 3815383 times.
|
6150689 | if (!tab->table()) continue; |
| 5116 | /* | ||
| 5117 | Tables that are within SJ-Materialization nests cannot have their | ||
| 5118 | conditions referring to preceding non-const tables. | ||
| 5119 | - If we're looking at the first SJM table, reset current_tables_map | ||
| 5120 | to refer to only allowed tables | ||
| 5121 | @see Item_equal::get_subst_item() | ||
| 5122 | @see eliminate_item_equal() | ||
| 5123 | */ | ||
| 5124 |
2/2✓ Branch 0 taken 8459 times.
✓ Branch 1 taken 3806892 times.
|
3815383 | if (sj_is_materialize_strategy(tab->get_sj_strategy())) { |
| 5125 | 8459 | const table_map sjm_inner_tables = tab->emb_sj_nest->sj_inner_tables; | |
| 5126 |
2/2✓ Branch 0 taken 4591 times.
✓ Branch 1 taken 3868 times.
|
8459 | if (!(sjm_inner_tables & current_tables_map)) { |
| 5127 | 4591 | saved_tables_map = current_tables_map; | |
| 5128 | 4591 | current_tables_map = initial_tables_map; | |
| 5129 | 4591 | prev_tables_map = (table_map)0; | |
| 5130 | } | ||
| 5131 | |||
| 5132 | 8459 | current_tables_map |= tab->table_ref->map(); | |
| 5133 | 8459 | tab->set_prefix_tables(current_tables_map, prev_tables_map); | |
| 5134 | 8459 | prev_tables_map = current_tables_map; | |
| 5135 | |||
| 5136 |
2/2✓ Branch 0 taken 4591 times.
✓ Branch 1 taken 3868 times.
|
8459 | if (!(sjm_inner_tables & ~current_tables_map)) { |
| 5137 | /* | ||
| 5138 | At the end of a semi-join materialization nest, | ||
| 5139 | add non-deterministic expressions to the last table of the nest: | ||
| 5140 | */ | ||
| 5141 | 4591 | tab->add_prefix_tables(RAND_TABLE_BIT); | |
| 5142 | |||
| 5143 | // Restore the previous map: | ||
| 5144 | 4591 | current_tables_map = saved_tables_map; | |
| 5145 | 4591 | prev_tables_map = | |
| 5146 |
1/2✓ Branch 0 taken 4591 times.
✗ Branch 1 not taken.
|
4591 | last_non_sjm_tab ? last_non_sjm_tab->prefix_tables() : (table_map)0; |
| 5147 | } | ||
| 5148 | } else { | ||
| 5149 | 3806892 | last_non_sjm_tab = tab; | |
| 5150 | 3806892 | current_tables_map |= tab->table_ref->map(); | |
| 5151 | 3806876 | tab->set_prefix_tables(current_tables_map, prev_tables_map); | |
| 5152 | 3806931 | prev_tables_map = current_tables_map; | |
| 5153 | } | ||
| 5154 | } | ||
| 5155 | /* | ||
| 5156 | Non-deterministic expressions must be added to the last table's condition. | ||
| 5157 | It solves problem with queries like SELECT * FROM t1 WHERE rand() > 0.5 | ||
| 5158 | */ | ||
| 5159 |
2/2✓ Branch 0 taken 1767481 times.
✓ Branch 1 taken 30 times.
|
1767511 | if (last_non_sjm_tab != nullptr) |
| 5160 | 1767481 | last_non_sjm_tab->add_prefix_tables(RAND_TABLE_BIT); | |
| 5161 | 1767506 | } | |
| 5162 | |||
| 5163 | /** | ||
| 5164 | Calculate best possible join order and initialize the join structure. | ||
| 5165 | |||
| 5166 | @return true if success, false if error. | ||
| 5167 | |||
| 5168 | The JOIN object is populated with statistics about the query, | ||
| 5169 | and a plan with table order and access method selection is made. | ||
| 5170 | |||
| 5171 | The list of tables to be optimized is taken from query_block->leaf_tables. | ||
| 5172 | JOIN::where_cond is also used in the optimization. | ||
| 5173 | As a side-effect, JOIN::keyuse_array is populated with key_use information. | ||
| 5174 | |||
| 5175 | Here is an overview of the logic of this function: | ||
| 5176 | |||
| 5177 | - Initialize JOIN data structures and setup basic dependencies between tables. | ||
| 5178 | |||
| 5179 | - Update dependencies based on join information. | ||
| 5180 | |||
| 5181 | - Make key descriptions (update_ref_and_keys()). | ||
| 5182 | |||
| 5183 | - Pull out semi-join tables based on table dependencies. | ||
| 5184 | |||
| 5185 | - Extract tables with zero or one rows as const tables. | ||
| 5186 | |||
| 5187 | - Read contents of const tables, substitute columns from these tables with | ||
| 5188 | actual data. Also keep track of empty tables vs. one-row tables. | ||
| 5189 | |||
| 5190 | - After const table extraction based on row count, more tables may | ||
| 5191 | have become functionally dependent. Extract these as const tables. | ||
| 5192 | |||
| 5193 | - Add new sargable predicates based on retrieved const values. | ||
| 5194 | |||
| 5195 | - Calculate number of rows to be retrieved from each table. | ||
| 5196 | |||
| 5197 | - Calculate cost of potential semi-join materializations. | ||
| 5198 | |||
| 5199 | - Calculate best possible join order based on available statistics. | ||
| 5200 | |||
| 5201 | - Fill in remaining information for the generated join order. | ||
| 5202 | */ | ||
| 5203 | |||
| 5204 | 1866955 | bool JOIN::make_join_plan() { | |
| 5205 |
1/2✓ Branch 0 taken 1866986 times.
✗ Branch 1 not taken.
|
1866955 | DBUG_TRACE; |
| 5206 | |||
| 5207 | 1866986 | SARGABLE_PARAM *sargables = nullptr; | |
| 5208 | |||
| 5209 | 1866986 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 5210 | |||
| 5211 |
3/4✓ Branch 0 taken 1866988 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1866986 times.
|
1866986 | if (init_planner_arrays()) // Create and initialize the arrays |
| 5212 | 2 | return true; | |
| 5213 | |||
| 5214 | // Outer join dependencies were initialized above, now complete the analysis. | ||
| 5215 |
6/6✓ Branch 0 taken 1671716 times.
✓ Branch 1 taken 195270 times.
✓ Branch 2 taken 494 times.
✓ Branch 3 taken 1671222 times.
✓ Branch 4 taken 195764 times.
✓ Branch 5 taken 1671222 times.
|
1866986 | if (query_block->outer_join || query_block->is_recursive()) { |
| 5216 |
3/4✓ Branch 0 taken 195755 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 195751 times.
|
195764 | if (propagate_dependencies()) { |
| 5217 | /* | ||
| 5218 | Catch illegal join order. | ||
| 5219 | SQL2011 forbids: | ||
| 5220 | WITH RECURSIVE rec AS ( | ||
| 5221 | ... UNION ALL SELECT ... FROM tbl LEFT JOIN rec ON...)c... | ||
| 5222 | MySQL also forbids the same query with STRAIGHT_JOIN instead of LEFT | ||
| 5223 | JOIN, because the algorithm of with-recursive imposes that "rec" be | ||
| 5224 | first in plan, i.e. "tbl" depends on "rec", but STRAIGHT_JOIN imposes | ||
| 5225 | the opposite dependency. | ||
| 5226 | */ | ||
| 5227 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | assert(query_block->is_recursive()); |
| 5228 | 4 | my_error(ER_CTE_RECURSIVE_FORBIDDEN_JOIN_ORDER, MYF(0), | |
| 5229 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | query_block->recursive_reference->alias); |
| 5230 | 4 | return true; | |
| 5231 | } | ||
| 5232 | 195751 | init_key_dependencies(); | |
| 5233 | } | ||
| 5234 | |||
| 5235 |
2/2✓ Branch 0 taken 2711 times.
✓ Branch 1 taken 1864255 times.
|
1866967 | if (unlikely(trace->is_started())) |
| 5236 |
1/2✓ Branch 0 taken 2711 times.
✗ Branch 1 not taken.
|
2711 | trace_table_dependencies(trace, join_tab, primary_tables); |
| 5237 | |||
| 5238 | // Build the key access information, which is the basis for ref access. | ||
| 5239 |
4/4✓ Branch 0 taken 631787 times.
✓ Branch 1 taken 1235179 times.
✓ Branch 2 taken 5671 times.
✓ Branch 3 taken 626116 times.
|
1866966 | if (where_cond || query_block->outer_join) { |
| 5240 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1240838 times.
|
1240838 | if (update_ref_and_keys(thd, &keyuse_array, join_tab, tables, where_cond, |
| 5241 |
1/2✓ Branch 0 taken 1240838 times.
✗ Branch 1 not taken.
|
1240850 | ~query_block->outer_join, query_block, &sargables)) |
| 5242 | ✗ | return true; | |
| 5243 | } | ||
| 5244 | |||
| 5245 | /* | ||
| 5246 | Pull out semi-join tables based on dependencies. Dependencies are valid | ||
| 5247 | throughout the lifetime of a query, so this operation can be performed | ||
| 5248 | on the first optimization only. | ||
| 5249 | */ | ||
| 5250 |
6/8✓ Branch 0 taken 1755767 times.
✓ Branch 1 taken 111187 times.
✓ Branch 2 taken 1755767 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 20542 times.
✓ Branch 5 taken 1735225 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1866954 times.
|
1887496 | if (!query_block->sj_pullout_done && !query_block->sj_nests.empty() && |
| 5251 |
2/4✓ Branch 0 taken 20542 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20542 times.
|
20542 | pull_out_semijoin_tables(this)) |
| 5252 | ✗ | return true; | |
| 5253 | |||
| 5254 | 1866954 | query_block->sj_pullout_done = true; | |
| 5255 | 1866954 | const uint sj_nests = query_block->sj_nests.size(); // Changed by pull-out | |
| 5256 | |||
| 5257 |
2/2✓ Branch 0 taken 1860869 times.
✓ Branch 1 taken 6080 times.
|
1866929 | if (!(query_block->active_options() & OPTION_NO_CONST_TABLES)) { |
| 5258 | // Detect tables that are const (0 or 1 row) and read their contents. | ||
| 5259 |
2/4✓ Branch 0 taken 1860915 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1860915 times.
|
1860869 | if (extract_const_tables()) return true; |
| 5260 | |||
| 5261 | // Detect tables that are functionally dependent on const values. | ||
| 5262 |
3/4✓ Branch 0 taken 1860912 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 1860862 times.
|
1860915 | if (extract_func_dependent_tables()) return true; |
| 5263 | } | ||
| 5264 | // Possibly able to create more sargable predicates from const rows. | ||
| 5265 |
5/6✓ Branch 0 taken 127380 times.
✓ Branch 1 taken 1739562 times.
✓ Branch 2 taken 118985 times.
✓ Branch 3 taken 8395 times.
✓ Branch 4 taken 118985 times.
✗ Branch 5 not taken.
|
1866942 | if (const_tables && sargables) update_sargable_from_const(sargables); |
| 5266 | |||
| 5267 | // Make a first estimate of the fanout for each table in the query block. | ||
| 5268 |
2/4✓ Branch 0 taken 1866921 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1866921 times.
|
1866942 | if (estimate_rowcount()) return true; |
| 5269 | |||
| 5270 | /* | ||
| 5271 | Apply join order hints, with the exception of | ||
| 5272 | JOIN_FIXED_ORDER and STRAIGHT_JOIN. | ||
| 5273 | */ | ||
| 5274 |
4/4✓ Branch 0 taken 7618 times.
✓ Branch 1 taken 1859303 times.
✓ Branch 2 taken 7613 times.
✓ Branch 3 taken 1859308 times.
|
1874539 | if (query_block->opt_hints_qb && |
| 5275 |
2/2✓ Branch 0 taken 7613 times.
✓ Branch 1 taken 5 times.
|
7618 | !(query_block->active_options() & SELECT_STRAIGHT_JOIN)) |
| 5276 |
1/2✓ Branch 0 taken 7613 times.
✗ Branch 1 not taken.
|
7613 | query_block->opt_hints_qb->apply_join_order_hints(this); |
| 5277 | |||
| 5278 |
2/2✓ Branch 0 taken 19232 times.
✓ Branch 1 taken 1847689 times.
|
1866921 | if (sj_nests) { |
| 5279 |
1/2✓ Branch 0 taken 19232 times.
✗ Branch 1 not taken.
|
19232 | set_semijoin_embedding(); |
| 5280 |
1/2✓ Branch 0 taken 19232 times.
✗ Branch 1 not taken.
|
19232 | query_block->update_semijoin_strategies(thd); |
| 5281 | } | ||
| 5282 | |||
| 5283 |
3/4✓ Branch 0 taken 1767448 times.
✓ Branch 1 taken 99396 times.
✓ Branch 2 taken 1767507 times.
✗ Branch 3 not taken.
|
1866921 | if (!plan_is_const()) optimize_keyuse(); |
| 5284 | |||
| 5285 | 1866903 | allow_outer_refs = true; | |
| 5286 | |||
| 5287 |
5/8✓ Branch 0 taken 19232 times.
✓ Branch 1 taken 1847671 times.
✓ Branch 2 taken 19232 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19232 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1866903 times.
|
1866903 | if (sj_nests && optimize_semijoin_nests_for_materialization(this)) |
| 5288 | ✗ | return true; | |
| 5289 | |||
| 5290 | // Choose the table order based on analysis done so far. | ||
| 5291 |
4/6✓ Branch 0 taken 1866917 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1866934 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 1866925 times.
|
1866903 | if (Optimize_table_order(thd, this, nullptr).choose_table_order()) |
| 5292 | 9 | return true; | |
| 5293 | |||
| 5294 |
3/4✓ Branch 0 taken 1866918 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1866916 times.
|
1866925 | DBUG_EXECUTE_IF("bug13820776_1", thd->killed = THD::KILL_QUERY;); |
| 5295 |
6/8✓ Branch 0 taken 1866924 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1866913 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 1866883 times.
✓ Branch 6 taken 22 times.
✓ Branch 7 taken 1866883 times.
|
1866918 | if (thd->killed || thd->is_error()) return true; |
| 5296 | |||
| 5297 | // If this is a subquery, decide between In-to-exists and materialization | ||
| 5298 |
7/8✓ Branch 0 taken 106041 times.
✓ Branch 1 taken 1760848 times.
✓ Branch 2 taken 106041 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 106032 times.
✓ Branch 6 taken 9 times.
✓ Branch 7 taken 1866880 times.
|
1866883 | if (query_expression()->item && decide_subquery_strategy()) return true; |
| 5299 | |||
| 5300 |
1/2✓ Branch 0 taken 1866819 times.
✗ Branch 1 not taken.
|
1866880 | refine_best_rowcount(); |
| 5301 | |||
| 5302 | 3733953 | if (!(thd->variables.option_bits & OPTION_BIG_SELECTS) && | |
| 5303 |
6/6✓ Branch 0 taken 315 times.
✓ Branch 1 taken 1866504 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 303 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 1866807 times.
|
1866831 | best_read > (double)thd->variables.max_join_size && |
| 5304 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | !thd->lex->is_explain()) { /* purecov: inspected */ |
| 5305 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | my_error(ER_TOO_BIG_SELECT, MYF(0)); |
| 5306 | 12 | error = -1; | |
| 5307 | 12 | return true; | |
| 5308 | } | ||
| 5309 | |||
| 5310 | 1866807 | positions = nullptr; // But keep best_positions for get_best_combination | |
| 5311 | |||
| 5312 | // Generate an execution plan from the found optimal join order. | ||
| 5313 |
2/4✓ Branch 0 taken 1866880 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1866880 times.
|
1866807 | if (get_best_combination()) return true; |
| 5314 | |||
| 5315 | // Cleanup after update_ref_and_keys has added keys for derived tables. | ||
| 5316 |
3/4✓ Branch 0 taken 177564 times.
✓ Branch 1 taken 1689316 times.
✓ Branch 2 taken 177564 times.
✗ Branch 3 not taken.
|
1866880 | if (query_block->materialized_derived_table_count) finalize_derived_keys(); |
| 5317 | |||
| 5318 | // No need for this struct after new JOIN_TAB array is set up. | ||
| 5319 | 1866880 | best_positions = nullptr; | |
| 5320 | |||
| 5321 | // Some called function may still set error status unnoticed | ||
| 5322 |
2/4✓ Branch 0 taken 1866882 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1866882 times.
|
1866880 | if (thd->is_error()) return true; |
| 5323 | |||
| 5324 | // There is at least one empty const table | ||
| 5325 |
2/2✓ Branch 0 taken 50202 times.
✓ Branch 1 taken 1816680 times.
|
1866882 | if (const_table_map != found_const_table_map) |
| 5326 | 50202 | zero_result_cause = "no matching row in const table"; | |
| 5327 | |||
| 5328 | 1866882 | return false; | |
| 5329 | 1866990 | } | |
| 5330 | |||
| 5331 | /** | ||
| 5332 | Initialize scratch arrays for the join order optimization | ||
| 5333 | |||
| 5334 | @returns false if success, true if error | ||
| 5335 | |||
| 5336 | @note If something fails during initialization, JOIN::cleanup() | ||
| 5337 | will free anything that has been partially allocated and set up. | ||
| 5338 | Arrays are created in the execution mem_root, so they will be | ||
| 5339 | deleted automatically when the mem_root is re-initialized. | ||
| 5340 | */ | ||
| 5341 | |||
| 5342 | 1866941 | bool JOIN::init_planner_arrays() { | |
| 5343 | // Up to one extra slot per semi-join nest is needed (if materialized) | ||
| 5344 | 1866941 | const uint sj_nests = query_block->sj_nests.size(); | |
| 5345 | 1866955 | const uint table_count = query_block->leaf_table_count; | |
| 5346 | |||
| 5347 |
2/4✓ Branch 0 taken 1866977 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1866982 times.
✗ Branch 3 not taken.
|
1866955 | assert(primary_tables == 0 && tables == 0); |
| 5348 | |||
| 5349 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1866979 times.
|
1866982 | if (!(join_tab = alloc_jtab_array(thd, table_count))) return true; |
| 5350 | |||
| 5351 | /* | ||
| 5352 | We add 2 cells: | ||
| 5353 | - because planning stage uses 0-termination so needs +1 | ||
| 5354 | - because after get_best_combination, we don't use 0-termination but | ||
| 5355 | need +2, to host at most 2 tmp sort/group/distinct tables. | ||
| 5356 | */ | ||
| 5357 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1866965 times.
|
1866965 | if (!(best_ref = (JOIN_TAB **)thd->alloc( |
| 5358 | sizeof(JOIN_TAB *) * | ||
| 5359 | 1866979 | (table_count + sj_nests + 2 + m_windows.elements)))) | |
| 5360 | ✗ | return true; | |
| 5361 | |||
| 5362 | // sort/group tmp tables have no map | ||
| 5363 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1866973 times.
|
1866973 | if (!(map2table = (JOIN_TAB **)thd->alloc(sizeof(JOIN_TAB *) * |
| 5364 | 1866965 | (table_count + sj_nests)))) | |
| 5365 | ✗ | return true; | |
| 5366 | |||
| 5367 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1866978 times.
|
1866973 | if (!(positions = new (thd->mem_root) POSITION[table_count])) return true; |
| 5368 | |||
| 5369 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1866979 times.
|
1866978 | if (!(best_positions = new (thd->mem_root) POSITION[table_count + sj_nests])) |
| 5370 | ✗ | return true; | |
| 5371 | |||
| 5372 | /* | ||
| 5373 | Initialize data structures for tables to be joined. | ||
| 5374 | Initialize dependencies between tables. | ||
| 5375 | */ | ||
| 5376 | 1866979 | JOIN_TAB **best_ref_p = best_ref; | |
| 5377 | 1866979 | TABLE_LIST *tl = query_block->leaf_tables; | |
| 5378 | |||
| 5379 |
2/2✓ Branch 0 taken 3951399 times.
✓ Branch 1 taken 1866974 times.
|
5818373 | for (JOIN_TAB *tab = join_tab; tl; tab++, tl = tl->next_leaf, best_ref_p++) { |
| 5380 | 3951399 | *best_ref_p = tab; | |
| 5381 | 3951399 | TABLE *const table = tl->table; | |
| 5382 | 3951399 | tab->table_ref = tl; | |
| 5383 | 3951399 | tab->set_table(table); | |
| 5384 | 3951387 | const int err = tl->fetch_number_of_rows(); | |
| 5385 | |||
| 5386 | // Initialize the cost model for the table | ||
| 5387 | 3951425 | table->init_cost_model(cost_model()); | |
| 5388 | |||
| 5389 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 3951391 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
3951398 | DBUG_EXECUTE_IF("bug11747970_raise_error", { |
| 5390 | if (!err) { | ||
| 5391 | my_error(ER_UNKNOWN_ERROR, MYF(0)); | ||
| 5392 | return true; | ||
| 5393 | } | ||
| 5394 | }); | ||
| 5395 | |||
| 5396 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3951389 times.
|
3951391 | if (err) { |
| 5397 | 2 | table->file->print_error(err, MYF(0)); | |
| 5398 | 2 | return true; | |
| 5399 | } | ||
| 5400 | 3951389 | all_table_map |= tl->map(); | |
| 5401 | 3951389 | tab->set_join(this); | |
| 5402 | |||
| 5403 |
6/6✓ Branch 0 taken 3893632 times.
✓ Branch 1 taken 57764 times.
✓ Branch 2 taken 2668 times.
✓ Branch 3 taken 3890972 times.
✓ Branch 4 taken 60432 times.
✓ Branch 5 taken 3890972 times.
|
3951386 | if (tl->is_updated() || tl->is_deleted()) { |
| 5404 | // As we update or delete rows, we can't read the index | ||
| 5405 | 60432 | table->no_keyread = true; | |
| 5406 | } | ||
| 5407 | |||
| 5408 | 3951404 | tab->dependent = tl->dep_tables; // Initialize table dependencies | |
| 5409 |
2/2✓ Branch 0 taken 716 times.
✓ Branch 1 taken 3950668 times.
|
3951404 | if (query_block->is_recursive()) { |
| 5410 |
2/2✓ Branch 0 taken 215 times.
✓ Branch 1 taken 501 times.
|
716 | if (query_block->recursive_reference != tl) |
| 5411 | // Recursive reference must go first | ||
| 5412 | 215 | tab->dependent |= query_block->recursive_reference->map(); | |
| 5413 | else { | ||
| 5414 | // Recursive reference mustn't use any index | ||
| 5415 | 501 | table->covering_keys.clear_all(); | |
| 5416 | 501 | table->keys_in_use_for_group_by.clear_all(); | |
| 5417 | 501 | table->keys_in_use_for_order_by.clear_all(); | |
| 5418 | } | ||
| 5419 | } | ||
| 5420 |
2/2✓ Branch 0 taken 164664 times.
✓ Branch 1 taken 3786713 times.
|
3951377 | if (tl->schema_table) table->file->stats.records = 2; |
| 5421 | 3951377 | table->quick_condition_rows = table->file->stats.records; | |
| 5422 | |||
| 5423 | 3951377 | tab->init_join_cond_ref(tl); | |
| 5424 | |||
| 5425 |
2/2✓ Branch 0 taken 7347 times.
✓ Branch 1 taken 3944031 times.
|
3951381 | if (tl->outer_join_nest()) { |
| 5426 | // tab belongs to a nested join, maybe to several embedding joins | ||
| 5427 | 7347 | tab->embedding_map = 0; | |
| 5428 |
2/2✓ Branch 0 taken 9319 times.
✓ Branch 1 taken 7347 times.
|
16666 | for (TABLE_LIST *embedding = tl->embedding; embedding; |
| 5429 | 9319 | embedding = embedding->embedding) { | |
| 5430 | 9319 | NESTED_JOIN *const nested_join = embedding->nested_join; | |
| 5431 | 9319 | tab->embedding_map |= nested_join->nj_map; | |
| 5432 | 9319 | tab->dependent |= embedding->dep_tables; | |
| 5433 | } | ||
| 5434 |
2/2✓ Branch 0 taken 526237 times.
✓ Branch 1 taken 3417786 times.
|
3944031 | } else if (tab->join_cond()) { |
| 5435 | // tab is the only inner table of an outer join | ||
| 5436 | 526237 | tab->embedding_map = 0; | |
| 5437 |
2/2✓ Branch 0 taken 5316 times.
✓ Branch 1 taken 526237 times.
|
531553 | for (TABLE_LIST *embedding = tl->embedding; embedding; |
| 5438 | 5316 | embedding = embedding->embedding) | |
| 5439 | 5316 | tab->embedding_map |= embedding->nested_join->nj_map; | |
| 5440 | } | ||
| 5441 | |||
| 5442 |
6/6✓ Branch 0 taken 176134 times.
✓ Branch 1 taken 3775255 times.
✓ Branch 2 taken 564 times.
✓ Branch 3 taken 175575 times.
✓ Branch 4 taken 564 times.
✓ Branch 5 taken 3950830 times.
|
3951370 | if (tl->is_derived() && tl->derived_query_expression()->m_lateral_deps) |
| 5443 | 564 | has_lateral = true; | |
| 5444 | |||
| 5445 | 3951394 | tables++; // Count number of initialized tables | |
| 5446 | } | ||
| 5447 | |||
| 5448 | 1866974 | primary_tables = tables; | |
| 5449 | 1866974 | *best_ref_p = nullptr; // Last element of array must be NULL | |
| 5450 | |||
| 5451 | 1866974 | return false; | |
| 5452 | } | ||
| 5453 | |||
| 5454 | /** | ||
| 5455 | Propagate dependencies between tables due to outer join relations. | ||
| 5456 | |||
| 5457 | @returns false if success, true if error | ||
| 5458 | |||
| 5459 | Build transitive closure for relation 'to be dependent on'. | ||
| 5460 | This will speed up the plan search for many cases with outer joins, | ||
| 5461 | as well as allow us to catch illegal cross references. | ||
| 5462 | Warshall's algorithm is used to build the transitive closure. | ||
| 5463 | As we may restart the outer loop up to 'table_count' times, the | ||
| 5464 | complexity of the algorithm is O((number of tables)^3). | ||
| 5465 | However, most of the iterations will be shortcircuited when | ||
| 5466 | there are no dependencies to propagate. | ||
| 5467 | */ | ||
| 5468 | |||
| 5469 | 195823 | bool JOIN::propagate_dependencies() { | |
| 5470 |
2/2✓ Branch 0 taken 1210951 times.
✓ Branch 1 taken 195878 times.
|
1406829 | for (uint i = 0; i < tables; i++) { |
| 5471 |
2/2✓ Branch 0 taken 676654 times.
✓ Branch 1 taken 534297 times.
|
1210951 | if (!join_tab[i].dependent) continue; |
| 5472 | |||
| 5473 | // Add my dependencies to other tables depending on me | ||
| 5474 | uint j; | ||
| 5475 | JOIN_TAB *tab; | ||
| 5476 |
2/2✓ Branch 0 taken 3332300 times.
✓ Branch 1 taken 534326 times.
|
3866626 | for (j = 0, tab = join_tab; j < tables; j++, tab++) { |
| 5477 |
2/2✓ Branch 0 taken 339750 times.
✓ Branch 1 taken 2992605 times.
|
3332300 | if (tab->dependent & join_tab[i].table_ref->map()) { |
| 5478 | 339750 | const table_map was_dependent = tab->dependent; | |
| 5479 | 339750 | tab->dependent |= join_tab[i].dependent; | |
| 5480 | /* | ||
| 5481 | If we change dependencies for a table we already have | ||
| 5482 | processed: Redo dependency propagation from this table. | ||
| 5483 | */ | ||
| 5484 |
4/4✓ Branch 0 taken 387 times.
✓ Branch 1 taken 339363 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 361 times.
|
339750 | if (i > j && tab->dependent != was_dependent) { |
| 5485 | 26 | i = j - 1; | |
| 5486 | 26 | break; | |
| 5487 | } | ||
| 5488 | } | ||
| 5489 | } | ||
| 5490 | } | ||
| 5491 | |||
| 5492 | 195878 | JOIN_TAB *const tab_end = join_tab + tables; | |
| 5493 |
2/2✓ Branch 0 taken 1210897 times.
✓ Branch 1 taken 195802 times.
|
1406699 | for (JOIN_TAB *tab = join_tab; tab < tab_end; tab++) { |
| 5494 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 1210821 times.
|
1210897 | if ((tab->dependent & tab->table_ref->map())) return true; |
| 5495 | } | ||
| 5496 | |||
| 5497 | 195802 | return false; | |
| 5498 | } | ||
| 5499 | |||
| 5500 | /** | ||
| 5501 | Extract const tables based on row counts. | ||
| 5502 | |||
| 5503 | @returns false if success, true if error | ||
| 5504 | |||
| 5505 | This extraction must be done for each execution. | ||
| 5506 | Tables containing exactly zero or one rows are marked as const, but | ||
| 5507 | notice the additional constraints checked below. | ||
| 5508 | Tables that are extracted have their rows read before actual execution | ||
| 5509 | starts and are placed in the beginning of the join_tab array. | ||
| 5510 | Thus, they do not take part in join order optimization process, | ||
| 5511 | which can significantly reduce the optimization time. | ||
| 5512 | The data read from these tables can also be regarded as "constant" | ||
| 5513 | throughout query execution, hence the column values can be used for | ||
| 5514 | additional constant propagation and extraction of const tables based | ||
| 5515 | on eq-ref properties. | ||
| 5516 | |||
| 5517 | The tables are given the type JT_SYSTEM. | ||
| 5518 | */ | ||
| 5519 | |||
| 5520 | 1860840 | bool JOIN::extract_const_tables() { | |
| 5521 | enum enum_const_table_extraction { | ||
| 5522 | extract_no_table = 0, | ||
| 5523 | extract_empty_table = 1, | ||
| 5524 | extract_const_table = 2 | ||
| 5525 | }; | ||
| 5526 | |||
| 5527 | 1860840 | JOIN_TAB *const tab_end = join_tab + tables; | |
| 5528 |
2/2✓ Branch 0 taken 3944499 times.
✓ Branch 1 taken 1860953 times.
|
5805452 | for (JOIN_TAB *tab = join_tab; tab < tab_end; tab++) { |
| 5529 | 3944499 | TABLE *const table = tab->table(); | |
| 5530 | 3944596 | TABLE_LIST *const tl = tab->table_ref; | |
| 5531 | 3944596 | enum enum_const_table_extraction extract_method = extract_const_table; | |
| 5532 | |||
| 5533 | 3944596 | const bool all_partitions_pruned_away = table->all_partitions_pruned_away; | |
| 5534 | |||
| 5535 |
2/2✓ Branch 0 taken 7314 times.
✓ Branch 1 taken 3937308 times.
|
3944596 | if (tl->outer_join_nest()) { |
| 5536 | /* | ||
| 5537 | Table belongs to a nested join, no candidate for const table extraction. | ||
| 5538 | */ | ||
| 5539 | 7314 | extract_method = extract_no_table; | |
| 5540 |
5/6✓ Branch 0 taken 36288 times.
✓ Branch 1 taken 3901020 times.
✓ Branch 2 taken 36288 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 36288 times.
✓ Branch 5 taken 3901020 times.
|
3937308 | } else if (tl->embedding && tl->embedding->is_sj_or_aj_nest()) { |
| 5541 | /* | ||
| 5542 | Table belongs to a semi-join. | ||
| 5543 | We do not currently pull out const tables from semi-join nests. | ||
| 5544 | */ | ||
| 5545 | 36288 | extract_method = extract_no_table; | |
| 5546 |
2/2✓ Branch 0 taken 520661 times.
✓ Branch 1 taken 3380361 times.
|
3901020 | } else if (tab->join_cond()) { |
| 5547 | // tab is the only inner table of an outer join, extract empty tables | ||
| 5548 | 520661 | extract_method = extract_empty_table; | |
| 5549 | } | ||
| 5550 |
4/4✓ Branch 0 taken 43602 times.
✓ Branch 1 taken 520658 times.
✓ Branch 2 taken 3380331 times.
✓ Branch 3 taken 33 times.
|
3944624 | switch (extract_method) { |
| 5551 | 43602 | case extract_no_table: | |
| 5552 | 43602 | break; | |
| 5553 | |||
| 5554 | 520658 | case extract_empty_table: | |
| 5555 | // Extract tables with zero rows, but only if statistics are exact | ||
| 5556 |
5/6✓ Branch 0 taken 520591 times.
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 520594 times.
✓ Branch 4 taken 63 times.
✓ Branch 5 taken 520595 times.
|
520722 | if ((table->file->stats.records == 0 || all_partitions_pruned_away) && |
| 5557 |
2/2✓ Branch 0 taken 63 times.
✓ Branch 1 taken 1 times.
|
64 | (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT)) |
| 5558 | 63 | mark_const_table(tab, nullptr); | |
| 5559 | 520657 | break; | |
| 5560 | |||
| 5561 | 3380331 | case extract_const_table: | |
| 5562 | /* | ||
| 5563 | Extract tables with zero or one rows, but do not extract tables that | ||
| 5564 | 1. are dependent upon other tables, or | ||
| 5565 | 2. have no exact statistics, or | ||
| 5566 | 3. are full-text searched | ||
| 5567 | */ | ||
| 5568 |
3/4✓ Branch 0 taken 2751730 times.
✓ Branch 1 taken 628561 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2751730 times.
|
3380291 | if ((table->s->system || table->file->stats.records <= 1 || |
| 5569 | 628601 | all_partitions_pruned_away) && | |
| 5570 |
2/2✓ Branch 0 taken 627707 times.
✓ Branch 1 taken 894 times.
|
628601 | !tab->dependent && // 1 |
| 5571 |
6/6✓ Branch 0 taken 3380291 times.
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 49056 times.
✓ Branch 3 taken 578637 times.
✓ Branch 4 taken 49009 times.
✓ Branch 5 taken 3331300 times.
|
6809710 | (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) && // 2 |
| 5572 |
2/2✓ Branch 0 taken 49009 times.
✓ Branch 1 taken 39 times.
|
49056 | !tl->is_fulltext_searched()) // 3 |
| 5573 | 49009 | mark_const_table(tab, nullptr); | |
| 5574 | 3380320 | break; | |
| 5575 | } | ||
| 5576 | } | ||
| 5577 | |||
| 5578 | // Read const tables (tables matching no more than 1 rows) | ||
| 5579 |
2/2✓ Branch 0 taken 1812203 times.
✓ Branch 1 taken 48750 times.
|
1860953 | if (!const_tables) return false; |
| 5580 | |||
| 5581 | 97822 | for (POSITION *p_pos = positions, *p_end = p_pos + const_tables; | |
| 5582 |
2/2✓ Branch 0 taken 49072 times.
✓ Branch 1 taken 48750 times.
|
97822 | p_pos < p_end; p_pos++) { |
| 5583 | 49072 | JOIN_TAB *const tab = p_pos->table; | |
| 5584 | 49072 | const int status = join_read_const_table(tab, p_pos); | |
| 5585 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 49072 times.
|
49072 | if (status > 0) |
| 5586 | ✗ | return true; | |
| 5587 |
2/2✓ Branch 0 taken 11462 times.
✓ Branch 1 taken 37610 times.
|
49072 | else if (status == 0) { |
| 5588 | 11462 | found_const_table_map |= tab->table_ref->map(); | |
| 5589 | 11462 | tab->table_ref->optimized_away = true; | |
| 5590 | } | ||
| 5591 | } | ||
| 5592 | |||
| 5593 | 48750 | return false; | |
| 5594 | } | ||
| 5595 | |||
| 5596 | /** | ||
| 5597 | Extract const tables based on functional dependencies. | ||
| 5598 | |||
| 5599 | @returns false if success, true if error | ||
| 5600 | |||
| 5601 | This extraction must be done for each execution. | ||
| 5602 | |||
| 5603 | Mark as const the tables that | ||
| 5604 | - are functionally dependent on constant values, or | ||
| 5605 | - are inner tables of an outer join and contain exactly zero or one rows | ||
| 5606 | |||
| 5607 | Tables that are extracted have their rows read before actual execution | ||
| 5608 | starts and are placed in the beginning of the join_tab array, just as | ||
| 5609 | described for JOIN::extract_const_tables(). | ||
| 5610 | |||
| 5611 | The tables are given the type JT_CONST. | ||
| 5612 | */ | ||
| 5613 | |||
| 5614 | 1860975 | bool JOIN::extract_func_dependent_tables() { | |
| 5615 | // loop until no more const tables are found | ||
| 5616 | bool ref_changed; | ||
| 5617 | // Tables referenced by others; if they're const the others may be too. | ||
| 5618 | table_map found_ref; | ||
| 5619 | do { | ||
| 5620 | 1860975 | more_const_tables_found: | |
| 5621 | 1860975 | ref_changed = false; | |
| 5622 | 1860975 | found_ref = 0; | |
| 5623 | |||
| 5624 | // Loop over all tables that are not already determined to be const | ||
| 5625 |
2/2✓ Branch 0 taken 3895719 times.
✓ Branch 1 taken 1860913 times.
|
5756632 | for (JOIN_TAB **pos = best_ref + const_tables; *pos; pos++) { |
| 5626 | 3895719 | JOIN_TAB *const tab = *pos; | |
| 5627 | 3895719 | TABLE *const table = tab->table(); | |
| 5628 | 3895794 | TABLE_LIST *const tl = tab->table_ref; | |
| 5629 | /* | ||
| 5630 | If equi-join condition by a key is null rejecting and after a | ||
| 5631 | substitution of a const table the key value happens to be null | ||
| 5632 | then we can state that there are no matches for this equi-join. | ||
| 5633 | */ | ||
| 5634 | 3895794 | Key_use *keyuse = tab->keyuse(); | |
| 5635 |
8/8✓ Branch 0 taken 2499587 times.
✓ Branch 1 taken 1396247 times.
✓ Branch 2 taken 518063 times.
✓ Branch 3 taken 1981530 times.
✓ Branch 4 taken 517849 times.
✓ Branch 5 taken 214 times.
✓ Branch 6 taken 517851 times.
✓ Branch 7 taken 3377989 times.
|
3895834 | if (keyuse && tab->join_cond() && !tab->embedding_map) { |
| 5636 | /* | ||
| 5637 | When performing an outer join operation if there are no matching rows | ||
| 5638 | for the single row of the outer table all the inner tables are to be | ||
| 5639 | null complemented and thus considered as constant tables. | ||
| 5640 | Here we apply this consideration to the case of outer join operations | ||
| 5641 | with a single inner table only because the case with nested tables | ||
| 5642 | would require a more thorough analysis. | ||
| 5643 | TODO. Apply single row substitution to null complemented inner tables | ||
| 5644 | for nested outer join operations. | ||
| 5645 | */ | ||
| 5646 |
2/2✓ Branch 0 taken 676215 times.
✓ Branch 1 taken 517779 times.
|
1193994 | while (keyuse->table_ref == tl) { |
| 5647 | 676215 | if (!(keyuse->val->used_tables() & ~const_table_map) && | |
| 5648 |
8/8✓ Branch 0 taken 156232 times.
✓ Branch 1 taken 520003 times.
✓ Branch 2 taken 57 times.
✓ Branch 3 taken 156127 times.
✓ Branch 4 taken 50 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 44 times.
✓ Branch 7 taken 676143 times.
|
676285 | keyuse->val->is_null() && keyuse->null_rejecting && |
| 5649 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 44 times.
|
50 | (tl->embedding == nullptr || |
| 5650 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | !tl->embedding->is_sj_or_aj_nest())) { |
| 5651 | 44 | table->set_null_row(); | |
| 5652 | 44 | table->const_table = true; | |
| 5653 | 44 | found_const_table_map |= tl->map(); | |
| 5654 | 44 | mark_const_table(tab, keyuse); | |
| 5655 | 56 | goto more_const_tables_found; | |
| 5656 | } | ||
| 5657 | 676143 | keyuse++; | |
| 5658 | } | ||
| 5659 | } | ||
| 5660 | |||
| 5661 |
2/2✓ Branch 0 taken 538763 times.
✓ Branch 1 taken 3357005 times.
|
3895768 | if (tab->dependent) // If dependent on some table |
| 5662 | { | ||
| 5663 | // All dependent tables must be const | ||
| 5664 |
2/2✓ Branch 0 taken 538374 times.
✓ Branch 1 taken 389 times.
|
538763 | if (tab->dependent & ~const_table_map) { |
| 5665 | 538374 | found_ref |= tab->dependent; | |
| 5666 | 538374 | continue; | |
| 5667 | } | ||
| 5668 | /* | ||
| 5669 | Mark a dependent table as constant if | ||
| 5670 | 1. it has exactly zero or one rows (it is a system table), and | ||
| 5671 | 2. it is not within a nested outer join, and | ||
| 5672 | 3. it does not have an expensive outer join condition. | ||
| 5673 | This is because we have to determine whether an outer-joined table | ||
| 5674 | has a real row or a null-extended row in the optimizer phase. | ||
| 5675 | We have no possibility to evaluate its join condition at | ||
| 5676 | execution time, when it is marked as a system table. | ||
| 5677 | */ | ||
| 5678 | 949 | if (table->file->stats.records <= 1L && // 1 | |
| 5679 |
4/4✓ Branch 0 taken 79 times.
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 44 times.
|
230 | (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) && // 1 |
| 5680 |
6/6✓ Branch 0 taken 151 times.
✓ Branch 1 taken 238 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 19 times.
✓ Branch 4 taken 35 times.
✓ Branch 5 taken 374 times.
|
655 | !tl->outer_join_nest() && // 2 |
| 5681 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 20 times.
|
51 | !(tab->join_cond() && tab->join_cond()->is_expensive())) // 3 |
| 5682 | { // system table | ||
| 5683 | 35 | mark_const_table(tab, nullptr); | |
| 5684 | const int status = | ||
| 5685 | 35 | join_read_const_table(tab, positions + const_tables - 1); | |
| 5686 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
|
35 | if (status > 0) |
| 5687 | ✗ | return true; | |
| 5688 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 15 times.
|
35 | else if (status == 0) |
| 5689 | 20 | found_const_table_map |= tl->map(); | |
| 5690 | 35 | continue; | |
| 5691 | 35 | } | |
| 5692 | } | ||
| 5693 | |||
| 5694 | // Check if table can be read by key or table only uses const refs | ||
| 5695 | |||
| 5696 |
2/2✓ Branch 0 taken 1978087 times.
✓ Branch 1 taken 1379193 times.
|
3357379 | if ((keyuse = tab->keyuse())) { |
| 5697 |
2/2✓ Branch 0 taken 3133423 times.
✓ Branch 1 taken 1896774 times.
|
5030197 | while (keyuse->table_ref == tl) { |
| 5698 | 3133423 | Key_use *const start_keyuse = keyuse; | |
| 5699 | 3133423 | const uint key = keyuse->key; | |
| 5700 | 3133423 | tab->keys().set_bit(key); // QQ: remove this ? | |
| 5701 | |||
| 5702 | 3133481 | table_map refs = 0; | |
| 5703 |
2/4✓ Branch 0 taken 3133509 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3133500 times.
✗ Branch 3 not taken.
|
3133481 | Key_map const_ref, eq_part; |
| 5704 | do { | ||
| 5705 |
7/8✓ Branch 0 taken 4044451 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4042128 times.
✓ Branch 3 taken 2323 times.
✓ Branch 4 taken 4041273 times.
✓ Branch 5 taken 855 times.
✓ Branch 6 taken 4041269 times.
✓ Branch 7 taken 3182 times.
|
4044470 | if (keyuse->val->type() != Item::NULL_ITEM && !keyuse->optimize) { |
| 5706 |
2/2✓ Branch 0 taken 505988 times.
✓ Branch 1 taken 3535281 times.
|
4041269 | if (!((~found_const_table_map) & keyuse->used_tables)) |
| 5707 | 505988 | const_ref.set_bit(keyuse->keypart); | |
| 5708 | else | ||
| 5709 | 3535281 | refs |= keyuse->used_tables; | |
| 5710 | 4041270 | eq_part.set_bit(keyuse->keypart); | |
| 5711 | } | ||
| 5712 | 4044420 | keyuse++; | |
| 5713 |
4/4✓ Branch 0 taken 2066799 times.
✓ Branch 1 taken 1977621 times.
✓ Branch 2 taken 910970 times.
✓ Branch 3 taken 1155829 times.
|
4044420 | } while (keyuse->table_ref == tl && keyuse->key == key); |
| 5714 | |||
| 5715 | /* | ||
| 5716 | Extract const tables with proper key dependencies. | ||
| 5717 | Exclude tables that | ||
| 5718 | 1. are full-text searched, or | ||
| 5719 | 2. are part of nested outer join, or | ||
| 5720 | 3. are part of semi-join, or | ||
| 5721 | 4. have an expensive outer join condition. | ||
| 5722 | 5. are blocked by handler for const table optimize. | ||
| 5723 | 6. are not going to be used, typically because they are streamed | ||
| 5724 | instead of materialized | ||
| 5725 | (see Query_expression::can_materialize_directly_into_result()). | ||
| 5726 | */ | ||
| 5727 | 3133450 | if (eq_part.is_prefix(table->key_info[key].user_defined_key_parts) && | |
| 5728 |
4/4✓ Branch 0 taken 2251698 times.
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 2251692 times.
✓ Branch 3 taken 40 times.
|
4503491 | !tl->is_fulltext_searched() && // 1 |
| 5729 | 2251698 | !tl->outer_join_nest() && // 2 | |
| 5730 |
6/6✓ Branch 0 taken 7553 times.
✓ Branch 1 taken 2244139 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 7546 times.
✓ Branch 4 taken 124 times.
✓ Branch 5 taken 2244019 times.
|
4495835 | !(tl->embedding && tl->embedding->is_sj_or_aj_nest()) && // 3 |
| 5731 |
2/4✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 124 times.
✗ Branch 3 not taken.
|
2244270 | !(tab->join_cond() && tab->join_cond()->is_expensive()) && // 4 |
| 5732 |
8/8✓ Branch 0 taken 2251759 times.
✓ Branch 1 taken 881693 times.
✓ Branch 2 taken 2244114 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 2242832 times.
✓ Branch 5 taken 1260 times.
✓ Branch 6 taken 2242834 times.
✓ Branch 7 taken 890607 times.
|
7629337 | !(table->file->ha_table_flags() & HA_BLOCK_CONST_TABLE) && // 5 |
| 5733 | 2244114 | table->is_created()) { // 6 | |
| 5734 |
2/2✓ Branch 0 taken 1779502 times.
✓ Branch 1 taken 463332 times.
|
2242834 | if (table->key_info[key].flags & HA_NOSAME) { |
| 5735 |
2/2✓ Branch 0 taken 81354 times.
✓ Branch 1 taken 1698158 times.
|
1779502 | if (const_ref == eq_part) { // Found everything for ref. |
| 5736 | 81354 | ref_changed = true; | |
| 5737 |
1/2✓ Branch 0 taken 81331 times.
✗ Branch 1 not taken.
|
81354 | mark_const_table(tab, start_keyuse); |
| 5738 |
3/4✓ Branch 0 taken 81331 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 81311 times.
|
81331 | if (create_ref_for_key(this, tab, start_keyuse, |
| 5739 | found_const_table_map)) | ||
| 5740 | 50 | return true; | |
| 5741 | const int status = | ||
| 5742 |
1/2✓ Branch 0 taken 81311 times.
✗ Branch 1 not taken.
|
81311 | join_read_const_table(tab, positions + const_tables - 1); |
| 5743 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 81281 times.
|
81311 | if (status > 0) |
| 5744 | 30 | return true; | |
| 5745 |
2/2✓ Branch 0 taken 78603 times.
✓ Branch 1 taken 2678 times.
|
81281 | else if (status == 0) |
| 5746 | 78603 | found_const_table_map |= tl->map(); | |
| 5747 | 81281 | break; | |
| 5748 | } else | ||
| 5749 | 1698158 | found_ref |= refs; // Table is const if all refs are const | |
| 5750 |
2/2✓ Branch 0 taken 66944 times.
✓ Branch 1 taken 396398 times.
|
463332 | } else if (const_ref == eq_part) |
| 5751 | 66944 | tab->const_keys.set_bit(key); | |
| 5752 | } | ||
| 5753 | } | ||
| 5754 | } | ||
| 5755 | } | ||
| 5756 | } while | ||
| 5757 | /* | ||
| 5758 | A new const table appeared, that is referenced by others, so re-check | ||
| 5759 | others: | ||
| 5760 | */ | ||
| 5761 |
4/4✓ Branch 0 taken 542 times.
✓ Branch 1 taken 1860371 times.
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 459 times.
|
1860913 | ((const_table_map & found_ref) && ref_changed); |
| 5762 | |||
| 5763 | 1860830 | return false; | |
| 5764 | } | ||
| 5765 | |||
| 5766 | /** | ||
| 5767 | Update info on indexes that can be used for search lookups as | ||
| 5768 | reading const tables may has added new sargable predicates. | ||
| 5769 | */ | ||
| 5770 | |||
| 5771 | 118985 | void JOIN::update_sargable_from_const(SARGABLE_PARAM *sargables) { | |
| 5772 |
2/2✓ Branch 0 taken 80 times.
✓ Branch 1 taken 118985 times.
|
119065 | for (; sargables->field; sargables++) { |
| 5773 | 80 | Field *const field = sargables->field; | |
| 5774 | 80 | JOIN_TAB *const tab = field->table->reginfo.join_tab; | |
| 5775 | 80 | Key_map possible_keys = field->key_start; | |
| 5776 | 80 | possible_keys.intersect(field->table->keys_in_use_for_query); | |
| 5777 | 80 | bool is_const = true; | |
| 5778 |
2/2✓ Branch 0 taken 116 times.
✓ Branch 1 taken 80 times.
|
196 | for (uint j = 0; j < sargables->num_values; j++) |
| 5779 |
1/2✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
|
116 | is_const &= sargables->arg_value[j]->const_item(); |
| 5780 |
2/2✓ Branch 0 taken 52 times.
✓ Branch 1 taken 28 times.
|
80 | if (is_const) { |
| 5781 | 52 | tab->const_keys.merge(possible_keys); | |
| 5782 | 52 | tab->keys().merge(possible_keys); | |
| 5783 | } | ||
| 5784 | } | ||
| 5785 | 118985 | } | |
| 5786 | |||
| 5787 | 3820807 | double find_worst_seeks(const TABLE *table, double num_rows, | |
| 5788 | double table_scan_cost) { | ||
| 5789 | /* | ||
| 5790 | Set a max value for the cost of seek operations we can expect | ||
| 5791 | when using key lookup. This can't be too high as otherwise we | ||
| 5792 | are likely to use table scan. | ||
| 5793 | */ | ||
| 5794 | double worst_seeks = | ||
| 5795 |
1/2✓ Branch 0 taken 3820886 times.
✗ Branch 1 not taken.
|
3820807 | min(table->file->worst_seek_times(num_rows / 10), table_scan_cost * 3); |
| 5796 |
1/2✓ Branch 0 taken 3820937 times.
✗ Branch 1 not taken.
|
3820886 | const double min_worst_seek = table->file->worst_seek_times(2.0); |
| 5797 | 3820937 | return std::max(worst_seeks, min_worst_seek); // Fix for small tables | |
| 5798 | } | ||
| 5799 | |||
| 5800 | /** | ||
| 5801 | Estimate the number of matched rows for each joined table. | ||
| 5802 | Set up range scan for tables that have proper predicates. | ||
| 5803 | |||
| 5804 | @returns false if success, true if error | ||
| 5805 | */ | ||
| 5806 | |||
| 5807 | 1866842 | bool JOIN::estimate_rowcount() { | |
| 5808 | 1866842 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 5809 |
1/2✓ Branch 0 taken 1866913 times.
✗ Branch 1 not taken.
|
1866842 | Opt_trace_object trace_wrapper(trace); |
| 5810 |
1/2✓ Branch 0 taken 1866919 times.
✗ Branch 1 not taken.
|
1866913 | Opt_trace_array trace_records(trace, "rows_estimation"); |
| 5811 | |||
| 5812 | 1866919 | JOIN_TAB *const tab_end = join_tab + tables; | |
| 5813 |
2/2✓ Branch 0 taken 3951220 times.
✓ Branch 1 taken 1866997 times.
|
5818217 | for (JOIN_TAB *tab = join_tab; tab < tab_end; tab++) { |
| 5814 |
1/2✓ Branch 0 taken 3951288 times.
✗ Branch 1 not taken.
|
3951220 | Opt_trace_object trace_table(trace); |
| 5815 |
1/2✓ Branch 0 taken 3951272 times.
✗ Branch 1 not taken.
|
3951288 | trace_table.add_utf8_table(tab->table_ref); |
| 5816 |
6/6✓ Branch 0 taken 3902145 times.
✓ Branch 1 taken 49110 times.
✓ Branch 2 taken 81322 times.
✓ Branch 3 taken 3820821 times.
✓ Branch 4 taken 130432 times.
✓ Branch 5 taken 3820821 times.
|
3951272 | if (tab->type() == JT_SYSTEM || tab->type() == JT_CONST) { |
| 5817 |
1/2✓ Branch 0 taken 130432 times.
✗ Branch 1 not taken.
|
130432 | trace_table.add("rows", 1) |
| 5818 |
1/2✓ Branch 0 taken 130432 times.
✗ Branch 1 not taken.
|
130432 | .add("cost", 1) |
| 5819 |
3/4✓ Branch 0 taken 49107 times.
✓ Branch 1 taken 81325 times.
✓ Branch 2 taken 130432 times.
✗ Branch 3 not taken.
|
130432 | .add_alnum("table_type", |
| 5820 | 130432 | (tab->type() == JT_SYSTEM) ? "system" : "const") | |
| 5821 |
1/2✓ Branch 0 taken 130432 times.
✗ Branch 1 not taken.
|
130432 | .add("empty", tab->table()->has_null_row()); |
| 5822 | |||
| 5823 | // Only one matching row and one block to read | ||
| 5824 | 130432 | tab->set_records(tab->found_records = 1); | |
| 5825 |
1/2✓ Branch 0 taken 130432 times.
✗ Branch 1 not taken.
|
130432 | tab->worst_seeks = tab->table()->file->worst_seek_times(1.0); |
| 5826 | 130432 | tab->read_time = tab->worst_seeks; | |
| 5827 | 130432 | continue; | |
| 5828 | } | ||
| 5829 | // Approximate number of found rows and cost to read them | ||
| 5830 | 3820821 | tab->set_records(tab->found_records = tab->table()->file->stats.records); | |
| 5831 |
1/2✓ Branch 0 taken 3820828 times.
✗ Branch 1 not taken.
|
3820793 | const Cost_estimate table_scan_time = tab->table()->file->table_scan_cost(); |
| 5832 | 3820828 | tab->read_time = table_scan_time.total_cost(); | |
| 5833 | |||
| 5834 | 3820939 | tab->worst_seeks = | |
| 5835 |
1/2✓ Branch 0 taken 3820939 times.
✗ Branch 1 not taken.
|
3820839 | find_worst_seeks(tab->table(), tab->found_records, tab->read_time); |
| 5836 | |||
| 5837 | /* | ||
| 5838 | Add to tab->const_keys the indexes for which all group fields or | ||
| 5839 | all select distinct fields participate in one index. | ||
| 5840 | Add to tab->skip_scan_keys indexes which can be used for skip | ||
| 5841 | scan access if no aggregates are present. | ||
| 5842 | */ | ||
| 5843 |
1/2✓ Branch 0 taken 3820866 times.
✗ Branch 1 not taken.
|
3820939 | add_loose_index_scan_and_skip_scan_keys(this, tab); |
| 5844 | |||
| 5845 | /* | ||
| 5846 | Perform range analysis if there are keys it could use (1). | ||
| 5847 | Don't do range analysis if on the inner side of an outer join (2). | ||
| 5848 | Do range analysis if on the inner side of a semi-join (3). | ||
| 5849 | */ | ||
| 5850 | 3820866 | TABLE_LIST *const tl = tab->table_ref; | |
| 5851 | 3820866 | if ((!tab->const_keys.is_clear_all() || | |
| 5852 |
6/6✓ Branch 0 taken 3356328 times.
✓ Branch 1 taken 464537 times.
✓ Branch 2 taken 36930 times.
✓ Branch 3 taken 3319434 times.
✓ Branch 4 taken 501115 times.
✓ Branch 5 taken 3319786 times.
|
4322332 | !tab->skip_scan_keys.is_clear_all()) && // (1) |
| 5853 |
2/2✓ Branch 0 taken 1830 times.
✓ Branch 1 taken 499637 times.
|
501467 | (!tl->embedding || // (2) |
| 5854 |
3/4✓ Branch 0 taken 1830 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1478 times.
✓ Branch 3 taken 352 times.
|
1830 | (tl->embedding && tl->embedding->is_sj_or_aj_nest()))) // (3) |
| 5855 | { | ||
| 5856 | /* | ||
| 5857 | This call fills tab->range_scan() with the best QUICK access method | ||
| 5858 | possible for this table, and only if it's better than table scan. | ||
| 5859 | It also fills tab->needed_reg. | ||
| 5860 | */ | ||
| 5861 |
1/2✓ Branch 0 taken 501115 times.
✗ Branch 1 not taken.
|
501115 | ha_rows records = get_quick_record_count(thd, tab, row_limit); |
| 5862 | |||
| 5863 |
5/8✓ Branch 0 taken 10018 times.
✓ Branch 1 taken 491097 times.
✓ Branch 2 taken 10018 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10018 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 501115 times.
|
501115 | if (records == 0 && thd->is_error()) return true; |
| 5864 | |||
| 5865 | /* | ||
| 5866 | Check for "impossible range", but make sure that we do not attempt | ||
| 5867 | to mark semi-joined tables as "const" (only semi-joined tables that | ||
| 5868 | are functionally dependent can be marked "const", and subsequently | ||
| 5869 | pulled out of their semi-join nests). | ||
| 5870 | */ | ||
| 5871 |
5/6✓ Branch 0 taken 10018 times.
✓ Branch 1 taken 491097 times.
✓ Branch 2 taken 10018 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9975 times.
✓ Branch 5 taken 491140 times.
|
511133 | if (records == 0 && tab->table()->reginfo.impossible_range && |
| 5872 |
3/4✓ Branch 0 taken 43 times.
✓ Branch 1 taken 9975 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 43 times.
|
10018 | (!(tl->embedding && tl->embedding->is_sj_or_aj_nest()))) { |
| 5873 | /* | ||
| 5874 | Impossible WHERE condition or join condition | ||
| 5875 | In case of join cond, mark that one empty NULL row is matched. | ||
| 5876 | In case of WHERE, don't set found_const_table_map to get the | ||
| 5877 | caller to abort with a zero row result. | ||
| 5878 | */ | ||
| 5879 |
1/2✓ Branch 0 taken 9975 times.
✗ Branch 1 not taken.
|
9975 | mark_const_table(tab, nullptr); |
| 5880 | 9975 | tab->set_type(JT_CONST); // Override setting made in mark_const_table() | |
| 5881 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9969 times.
|
9975 | if (tab->join_cond()) { |
| 5882 | // Generate an empty row | ||
| 5883 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | trace_table.add("returning_empty_null_row", true) |
| 5884 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | .add_alnum("cause", "impossible_on_condition"); |
| 5885 | 6 | found_const_table_map |= tl->map(); | |
| 5886 | 6 | tab->table()->set_null_row(); // All fields are NULL | |
| 5887 | } else { | ||
| 5888 |
2/4✓ Branch 0 taken 9969 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9969 times.
✗ Branch 3 not taken.
|
9969 | trace_table.add("rows", 0).add_alnum("cause", |
| 5889 | "impossible_where_condition"); | ||
| 5890 | } | ||
| 5891 | } | ||
| 5892 |
2/2✓ Branch 0 taken 143539 times.
✓ Branch 1 taken 357576 times.
|
501115 | if (records != HA_POS_ERROR) { |
| 5893 | 143539 | tab->found_records = records; | |
| 5894 |
2/2✓ Branch 0 taken 133509 times.
✓ Branch 1 taken 10030 times.
|
143539 | tab->read_time = tab->range_scan() ? tab->range_scan()->cost : 0.0; |
| 5895 | } | ||
| 5896 | } else { | ||
| 5897 |
1/2✓ Branch 0 taken 3319750 times.
✗ Branch 1 not taken.
|
6639563 | Opt_trace_object(trace, "table_scan") |
| 5898 |
1/2✓ Branch 0 taken 3319777 times.
✗ Branch 1 not taken.
|
3319750 | .add("rows", tab->found_records) |
| 5899 |
1/2✓ Branch 0 taken 3319777 times.
✗ Branch 1 not taken.
|
3319777 | .add("cost", tab->read_time); |
| 5900 | } | ||
| 5901 |
2/3✓ Branch 0 taken 3820866 times.
✓ Branch 1 taken 130432 times.
✗ Branch 2 not taken.
|
3951335 | } |
| 5902 | |||
| 5903 | 1866997 | return false; | |
| 5904 | 1866997 | } | |
| 5905 | |||
| 5906 | /** | ||
| 5907 | Set semi-join embedding join nest pointers. | ||
| 5908 | |||
| 5909 | Set pointer to embedding semi-join nest for all semi-joined tables. | ||
| 5910 | This is the closest semi-join or anti-join nest. | ||
| 5911 | Note that this must be done for every table inside all semi-join nests, | ||
| 5912 | even for tables within outer join nests embedded in semi-join nests. | ||
| 5913 | A table can never be part of multiple semi-join nests, hence no | ||
| 5914 | ambiguities can ever occur. | ||
| 5915 | Note also that the pointer is not set for TABLE_LIST objects that | ||
| 5916 | are outer join nests within semi-join nests. | ||
| 5917 | */ | ||
| 5918 | |||
| 5919 | 19232 | void JOIN::set_semijoin_embedding() { | |
| 5920 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19232 times.
|
19232 | assert(!query_block->sj_nests.empty()); |
| 5921 | |||
| 5922 | 19232 | JOIN_TAB *const tab_end = join_tab + primary_tables; | |
| 5923 | |||
| 5924 |
2/2✓ Branch 0 taken 63904 times.
✓ Branch 1 taken 19232 times.
|
83136 | for (JOIN_TAB *tab = join_tab; tab < tab_end; tab++) { |
| 5925 | 63904 | tab->emb_sj_nest = nullptr; | |
| 5926 |
2/2✓ Branch 0 taken 41045 times.
✓ Branch 1 taken 63904 times.
|
104949 | for (TABLE_LIST *tl = tab->table_ref; tl->embedding; tl = tl->embedding) { |
| 5927 |
2/2✓ Branch 0 taken 38289 times.
✓ Branch 1 taken 2756 times.
|
41045 | if (tl->embedding->is_sj_or_aj_nest()) { |
| 5928 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38289 times.
|
38289 | assert(!tab->emb_sj_nest); |
| 5929 | 38289 | tab->emb_sj_nest = tl->embedding; | |
| 5930 | // Let the up-walk continue, to assert there's no AJ/SJ nest above. | ||
| 5931 | } | ||
| 5932 | } | ||
| 5933 | } | ||
| 5934 | 19232 | } | |
| 5935 | |||
| 5936 | /** | ||
| 5937 | @brief Check if semijoin's compared types allow materialization. | ||
| 5938 | |||
| 5939 | @param[in,out] sj_nest Semi-join nest containing information about correlated | ||
| 5940 | expressions. Set nested_join->sjm.scan_allowed to true if | ||
| 5941 | MaterializeScan strategy allowed. Set nested_join->sjm.lookup_allowed | ||
| 5942 | to true if MaterializeLookup strategy allowed | ||
| 5943 | |||
| 5944 | @details | ||
| 5945 | This is a temporary fix for BUG#36752. | ||
| 5946 | |||
| 5947 | There are two subquery materialization strategies for semijoin: | ||
| 5948 | |||
| 5949 | 1. Materialize and do index lookups in the materialized table. See | ||
| 5950 | BUG#36752 for description of restrictions we need to put on the | ||
| 5951 | compared expressions. | ||
| 5952 | |||
| 5953 | In addition, since indexes are not supported for BLOB columns, | ||
| 5954 | this strategy can not be used if any of the columns in the | ||
| 5955 | materialized table will be BLOB/GEOMETRY columns. (Note that | ||
| 5956 | also columns for non-BLOB values that may be greater in size | ||
| 5957 | than CONVERT_IF_BIGGER_TO_BLOB, will be represented as BLOB | ||
| 5958 | columns.) | ||
| 5959 | |||
| 5960 | 2. Materialize and then do a full scan of the materialized table. | ||
| 5961 | The same criteria as for MaterializeLookup are applied, except that | ||
| 5962 | BLOB/GEOMETRY columns are allowed. | ||
| 5963 | */ | ||
| 5964 | |||
| 5965 | 9374 | static void semijoin_types_allow_materialization(TABLE_LIST *sj_nest) { | |
| 5966 |
1/2✓ Branch 0 taken 9374 times.
✗ Branch 1 not taken.
|
9374 | DBUG_TRACE; |
| 5967 | |||
| 5968 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9374 times.
|
9374 | assert(sj_nest->nested_join->sj_outer_exprs.size() == |
| 5969 | sj_nest->nested_join->sj_inner_exprs.size()); | ||
| 5970 | |||
| 5971 |
5/6✓ Branch 0 taken 9374 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 9372 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 9372 times.
|
18748 | if (sj_nest->nested_join->sj_outer_exprs.size() > MAX_REF_PARTS || |
| 5972 | 9374 | sj_nest->nested_join->sj_outer_exprs.size() == 0) { | |
| 5973 | // building an index is impossible | ||
| 5974 | 2 | sj_nest->nested_join->sjm.scan_allowed = false; | |
| 5975 | 2 | sj_nest->nested_join->sjm.lookup_allowed = false; | |
| 5976 | 2 | return; | |
| 5977 | } | ||
| 5978 | |||
| 5979 | 9372 | sj_nest->nested_join->sjm.scan_allowed = true; | |
| 5980 | 9372 | sj_nest->nested_join->sjm.lookup_allowed = true; | |
| 5981 | |||
| 5982 | 9372 | bool blobs_involved = false; | |
| 5983 | 9372 | uint total_lookup_index_length = 0; | |
| 5984 | uint max_key_length, max_key_part_length, max_key_parts; | ||
| 5985 | /* | ||
| 5986 | Maximum lengths for keys and key parts that are supported by | ||
| 5987 | the temporary table storage engine(s). | ||
| 5988 | */ | ||
| 5989 |
1/2✓ Branch 0 taken 9372 times.
✗ Branch 1 not taken.
|
9372 | get_max_key_and_part_length(&max_key_length, &max_key_part_length, |
| 5990 | &max_key_parts); | ||
| 5991 |
1/2✓ Branch 0 taken 9372 times.
✗ Branch 1 not taken.
|
9372 | auto it1 = sj_nest->nested_join->sj_outer_exprs.begin(); |
| 5992 |
1/2✓ Branch 0 taken 9372 times.
✗ Branch 1 not taken.
|
9372 | auto it2 = sj_nest->nested_join->sj_inner_exprs.begin(); |
| 5993 |
4/6✓ Branch 0 taken 18886 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18886 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10202 times.
✓ Branch 5 taken 8684 times.
|
29088 | while (it1 != sj_nest->nested_join->sj_outer_exprs.end() && |
| 5994 |
5/8✓ Branch 0 taken 10202 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10202 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10202 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10202 times.
✓ Branch 7 taken 8684 times.
|
29088 | it2 != sj_nest->nested_join->sj_inner_exprs.end()) { |
| 5995 |
2/4✓ Branch 0 taken 10202 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10202 times.
✗ Branch 3 not taken.
|
10202 | Item *outer = *it1++; |
| 5996 |
2/4✓ Branch 0 taken 10202 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10202 times.
✗ Branch 3 not taken.
|
10202 | Item *inner = *it2++; |
| 5997 |
4/8✓ Branch 0 taken 10202 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10202 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10202 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10202 times.
✗ Branch 7 not taken.
|
10202 | assert(outer->real_item() && inner->real_item()); |
| 5998 |
3/4✓ Branch 0 taken 10202 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 688 times.
✓ Branch 3 taken 9514 times.
|
10202 | if (!types_allow_materialization(outer, inner)) { |
| 5999 | 688 | sj_nest->nested_join->sjm.scan_allowed = false; | |
| 6000 | 688 | sj_nest->nested_join->sjm.lookup_allowed = false; | |
| 6001 | 688 | return; | |
| 6002 | } | ||
| 6003 |
1/2✓ Branch 0 taken 9514 times.
✗ Branch 1 not taken.
|
9514 | blobs_involved |= inner->is_blob_field(); |
| 6004 | |||
| 6005 | // Calculate the index length of materialized table | ||
| 6006 |
1/2✓ Branch 0 taken 9514 times.
✗ Branch 1 not taken.
|
9514 | const uint lookup_index_length = get_key_length_tmp_table(inner); |
| 6007 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9512 times.
|
9514 | if (lookup_index_length > max_key_part_length) |
| 6008 | 2 | sj_nest->nested_join->sjm.lookup_allowed = false; | |
| 6009 | 9514 | total_lookup_index_length += lookup_index_length; | |
| 6010 | } | ||
| 6011 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8682 times.
|
8684 | if (total_lookup_index_length > max_key_length) |
| 6012 | 2 | sj_nest->nested_join->sjm.lookup_allowed = false; | |
| 6013 | |||
| 6014 |
2/2✓ Branch 0 taken 272 times.
✓ Branch 1 taken 8412 times.
|
8684 | if (blobs_involved) sj_nest->nested_join->sjm.lookup_allowed = false; |
| 6015 | |||
| 6016 |
3/8✓ Branch 0 taken 8684 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8684 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8684 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
8684 | DBUG_PRINT("info", ("semijoin_types_allow_materialization: ok, allowed")); |
| 6017 |
2/2✓ Branch 0 taken 8684 times.
✓ Branch 1 taken 690 times.
|
9374 | } |
| 6018 | |||
| 6019 | /** | ||
| 6020 | Index dive can be skipped if the following conditions are satisfied: | ||
| 6021 | F1) For a single table query: | ||
| 6022 | a) FORCE INDEX applies to a single index. | ||
| 6023 | b) No subquery is present. | ||
| 6024 | c) Fulltext Index is not involved. | ||
| 6025 | d) No GROUP-BY or DISTINCT clause. | ||
| 6026 | e) No ORDER-BY clause. | ||
| 6027 | |||
| 6028 | F2) Not applicable to multi-table query. | ||
| 6029 | |||
| 6030 | F3) This optimization is not applicable to EXPLAIN queries. | ||
| 6031 | |||
| 6032 | @param tab JOIN_TAB object. | ||
| 6033 | @param thd THD object. | ||
| 6034 | */ | ||
| 6035 | 501115 | static bool check_skip_records_in_range_qualification(JOIN_TAB *tab, THD *thd) { | |
| 6036 | 501115 | Query_block *select = thd->lex->current_query_block(); | |
| 6037 | 501115 | TABLE *table = tab->table(); | |
| 6038 |
2/2✓ Branch 0 taken 1578 times.
✓ Branch 1 taken 64 times.
|
1642 | return ((table->force_index && |
| 6039 |
2/2✓ Branch 0 taken 1545 times.
✓ Branch 1 taken 33 times.
|
3220 | table->keys_in_use_for_query.bits_set() == 1) && // F1.a |
| 6040 | 1578 | select->parent_lex->is_single_level_stmt() && // F1.b | |
| 6041 |
2/2✓ Branch 0 taken 1544 times.
✓ Branch 1 taken 1 times.
|
1545 | !select->has_ft_funcs() && // F1.c |
| 6042 |
4/4✓ Branch 0 taken 1462 times.
✓ Branch 1 taken 82 times.
✓ Branch 2 taken 1456 times.
✓ Branch 3 taken 6 times.
|
1544 | (!select->is_grouped() && !select->is_distinct()) && // F1.d |
| 6043 |
4/4✓ Branch 0 taken 1306 times.
✓ Branch 1 taken 150 times.
✓ Branch 2 taken 1272 times.
✓ Branch 3 taken 34 times.
|
2762 | !select->is_ordered() && // F1.e |
| 6044 |
2/2✓ Branch 0 taken 1642 times.
✓ Branch 1 taken 499473 times.
|
504063 | select->join_list->size() == 1 && // F2 |
| 6045 |
2/2✓ Branch 0 taken 1192 times.
✓ Branch 1 taken 80 times.
|
502387 | !thd->lex->is_explain()); // F3 |
| 6046 | } | ||
| 6047 | |||
| 6048 | /***************************************************************************** | ||
| 6049 | Create JOIN_TABS, make a guess about the table types, | ||
| 6050 | Approximate how many records will be used in each table | ||
| 6051 | *****************************************************************************/ | ||
| 6052 | |||
| 6053 | /** | ||
| 6054 | Returns estimated number of rows that could be fetched by given | ||
| 6055 | access method. | ||
| 6056 | |||
| 6057 | The function calls the range optimizer to estimate the cost of the | ||
| 6058 | cheapest QUICK_* index access method to scan one or several of the | ||
| 6059 | 'keys' using the conditions 'select->cond'. The range optimizer | ||
| 6060 | compares several different types of 'quick select' methods (range | ||
| 6061 | scan, index merge, loose index scan) and selects the cheapest one. | ||
| 6062 | |||
| 6063 | If the best index access method is cheaper than a table- and an index | ||
| 6064 | scan, then the range optimizer also constructs the corresponding | ||
| 6065 | QUICK_* object and assigns it to select->quick. In most cases this | ||
| 6066 | is the QUICK_* object used at later (optimization and execution) | ||
| 6067 | phases. | ||
| 6068 | |||
| 6069 | @param thd Session that runs the query. | ||
| 6070 | @param tab JOIN_TAB of source table. | ||
| 6071 | @param limit maximum number of rows to select. | ||
| 6072 | |||
| 6073 | @note | ||
| 6074 | In case of valid range, a RowIterator object will be constructed and | ||
| 6075 | saved in select->quick. | ||
| 6076 | |||
| 6077 | @return Estimated number of result rows selected from 'tab'. | ||
| 6078 | |||
| 6079 | @retval HA_POS_ERROR For derived tables/views or if an error occur. | ||
| 6080 | @retval 0 If impossible query (i.e. certainly no rows will be | ||
| 6081 | selected.) | ||
| 6082 | */ | ||
| 6083 | 501115 | static ha_rows get_quick_record_count(THD *thd, JOIN_TAB *tab, ha_rows limit) { | |
| 6084 |
1/2✓ Branch 0 taken 501115 times.
✗ Branch 1 not taken.
|
501115 | DBUG_TRACE; |
| 6085 | uchar buff[STACK_BUFF_ALLOC]; | ||
| 6086 |
2/4✓ Branch 0 taken 501115 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 501115 times.
|
501115 | if (check_stack_overrun(thd, STACK_MIN_SIZE, buff)) |
| 6087 | ✗ | return 0; // Fatal error flag is set | |
| 6088 | 501115 | TABLE_LIST *const tl = tab->table_ref; | |
| 6089 | 1002230 | tab->set_skip_records_in_range( | |
| 6090 |
1/2✓ Branch 0 taken 501115 times.
✗ Branch 1 not taken.
|
501115 | check_skip_records_in_range_qualification(tab, thd)); |
| 6091 | |||
| 6092 | // Derived tables aren't filled yet, so no stats are available. | ||
| 6093 |
2/2✓ Branch 0 taken 500738 times.
✓ Branch 1 taken 377 times.
|
501115 | if (!tl->uses_materialization()) { |
| 6094 | AccessPath *range_scan; | ||
| 6095 | 500738 | Key_map keys_to_use = tab->const_keys; | |
| 6096 | 500738 | keys_to_use.merge(tab->skip_scan_keys); | |
| 6097 | MEM_ROOT temp_mem_root(key_memory_test_quick_select_exec, | ||
| 6098 | 500738 | thd->variables.range_alloc_block_size); | |
| 6099 |
3/4✓ Branch 0 taken 84617 times.
✓ Branch 1 taken 416121 times.
✓ Branch 2 taken 500738 times.
✗ Branch 3 not taken.
|
1417597 | int error = test_quick_select( |
| 6100 | thd, thd->mem_root, &temp_mem_root, keys_to_use, 0, | ||
| 6101 | 0, // empty table_map | ||
| 6102 | limit, | ||
| 6103 | false, // don't force quick range | ||
| 6104 | 500738 | ORDER_NOT_RELEVANT, tab->table(), tab->skip_records_in_range(), | |
| 6105 | 500738 | tab->join_cond() ? tab->join_cond() : tab->join()->where_cond, | |
| 6106 | 500738 | &tab->needed_reg, tab->table()->force_index, tab->join()->query_block, | |
| 6107 | &range_scan); | ||
| 6108 | 500738 | tab->set_range_scan(range_scan); | |
| 6109 | |||
| 6110 |
2/2✓ Branch 0 taken 133506 times.
✓ Branch 1 taken 367232 times.
|
500738 | if (error == 1) return range_scan->num_output_rows; |
| 6111 |
2/2✓ Branch 0 taken 10018 times.
✓ Branch 1 taken 357214 times.
|
367232 | if (error == -1) { |
| 6112 | 10018 | tl->table->reginfo.impossible_range = true; | |
| 6113 | 10018 | return 0; | |
| 6114 | } | ||
| 6115 |
5/8✓ Branch 0 taken 357214 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 357214 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 357209 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
|
357214 | DBUG_PRINT("warning", ("Couldn't use record count on const keypart")); |
| 6116 |
8/10✓ Branch 0 taken 357214 times.
✓ Branch 1 taken 143524 times.
✓ Branch 2 taken 362 times.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 362 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 362 times.
✓ Branch 8 taken 15 times.
✓ Branch 9 taken 362 times.
|
501115 | } else if (tl->is_table_function() || tl->materializable_is_const()) { |
| 6117 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | tl->fetch_number_of_rows(); |
| 6118 | 15 | return tl->table->file->stats.records; | |
| 6119 | } | ||
| 6120 | 357576 | return HA_POS_ERROR; | |
| 6121 | 501115 | } | |
| 6122 | |||
| 6123 | /* | ||
| 6124 | Get estimated record length for semi-join materialization temptable | ||
| 6125 | |||
| 6126 | SYNOPSIS | ||
| 6127 | get_tmp_table_rec_length() | ||
| 6128 | items IN subquery's select list. | ||
| 6129 | |||
| 6130 | DESCRIPTION | ||
| 6131 | Calculate estimated record length for semi-join materialization | ||
| 6132 | temptable. It's an estimate because we don't follow every bit of | ||
| 6133 | create_tmp_table()'s logic. This isn't necessary as the return value of | ||
| 6134 | this function is used only for cost calculations. | ||
| 6135 | |||
| 6136 | RETURN | ||
| 6137 | Length of the temptable record, in bytes | ||
| 6138 | */ | ||
| 6139 | |||
| 6140 | 11033 | static uint get_tmp_table_rec_length(const mem_root_deque<Item *> &items) { | |
| 6141 | 11033 | uint len = 0; | |
| 6142 |
8/14✓ Branch 0 taken 11033 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11033 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11033 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12040 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 12040 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 23073 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 12040 times.
✓ Branch 13 taken 11033 times.
|
23073 | for (Item *item : VisibleFields(items)) { |
| 6143 |
5/7✓ Branch 0 taken 12040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 264 times.
✓ Branch 3 taken 8496 times.
✓ Branch 4 taken 3144 times.
✓ Branch 5 taken 136 times.
✗ Branch 6 not taken.
|
12040 | switch (item->result_type()) { |
| 6144 | 264 | case REAL_RESULT: | |
| 6145 | 264 | len += sizeof(double); | |
| 6146 | 264 | break; | |
| 6147 | 8496 | case INT_RESULT: | |
| 6148 |
2/2✓ Branch 0 taken 8191 times.
✓ Branch 1 taken 305 times.
|
8496 | if (item->max_length >= (MY_INT32_NUM_DECIMAL_DIGITS - 1)) |
| 6149 | 8191 | len += 8; | |
| 6150 | else | ||
| 6151 | 305 | len += 4; | |
| 6152 | 8496 | break; | |
| 6153 | 3144 | case STRING_RESULT: | |
| 6154 | /* DATE/TIME and GEOMETRY fields have STRING_RESULT result type. */ | ||
| 6155 |
6/6✓ Branch 0 taken 2986 times.
✓ Branch 1 taken 158 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 2974 times.
✓ Branch 4 taken 170 times.
✓ Branch 5 taken 2974 times.
|
3144 | if (item->is_temporal() || item->data_type() == MYSQL_TYPE_GEOMETRY) |
| 6156 | 170 | len += 8; | |
| 6157 | else | ||
| 6158 | 2974 | len += item->max_length; | |
| 6159 | 3144 | break; | |
| 6160 | 136 | case DECIMAL_RESULT: | |
| 6161 | 136 | len += 10; | |
| 6162 | 136 | break; | |
| 6163 | ✗ | case ROW_RESULT: | |
| 6164 | default: | ||
| 6165 | ✗ | assert(0); /* purecov: deadcode */ | |
| 6166 | break; | ||
| 6167 | } | ||
| 6168 | } | ||
| 6169 | 11033 | return len; | |
| 6170 | } | ||
| 6171 | |||
| 6172 | /** | ||
| 6173 | Writes to the optimizer trace information about dependencies between | ||
| 6174 | tables. | ||
| 6175 | @param trace optimizer trace | ||
| 6176 | @param join_tabs all JOIN_TABs of the join | ||
| 6177 | @param table_count how many JOIN_TABs in the 'join_tabs' array | ||
| 6178 | */ | ||
| 6179 | 2711 | static void trace_table_dependencies(Opt_trace_context *trace, | |
| 6180 | JOIN_TAB *join_tabs, uint table_count) { | ||
| 6181 |
1/2✓ Branch 0 taken 2711 times.
✗ Branch 1 not taken.
|
2711 | Opt_trace_object trace_wrapper(trace); |
| 6182 |
1/2✓ Branch 0 taken 2711 times.
✗ Branch 1 not taken.
|
2711 | Opt_trace_array trace_dep(trace, "table_dependencies"); |
| 6183 |
2/2✓ Branch 0 taken 3207 times.
✓ Branch 1 taken 2711 times.
|
5918 | for (uint i = 0; i < table_count; i++) { |
| 6184 | 3207 | TABLE_LIST *table_ref = join_tabs[i].table_ref; | |
| 6185 |
1/2✓ Branch 0 taken 3207 times.
✗ Branch 1 not taken.
|
3207 | Opt_trace_object trace_one_table(trace); |
| 6186 |
2/4✓ Branch 0 taken 3207 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3207 times.
✗ Branch 3 not taken.
|
6414 | trace_one_table.add_utf8_table(table_ref).add( |
| 6187 | 3207 | "row_may_be_null", table_ref->table->is_nullable()); | |
| 6188 | 3207 | const table_map map = table_ref->map(); | |
| 6189 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3207 times.
|
3207 | assert(map < (1ULL << table_count)); |
| 6190 |
1/2✓ Branch 0 taken 3966 times.
✗ Branch 1 not taken.
|
3966 | for (uint j = 0; j < table_count; j++) { |
| 6191 |
2/2✓ Branch 0 taken 3207 times.
✓ Branch 1 taken 759 times.
|
3966 | if (map & (1ULL << j)) { |
| 6192 |
1/2✓ Branch 0 taken 3207 times.
✗ Branch 1 not taken.
|
3207 | trace_one_table.add("map_bit", j); |
| 6193 | 3207 | break; | |
| 6194 | } | ||
| 6195 | } | ||
| 6196 |
1/2✓ Branch 0 taken 3207 times.
✗ Branch 1 not taken.
|
3207 | Opt_trace_array depends_on(trace, "depends_on_map_bits"); |
| 6197 | static_assert(sizeof(table_ref->map()) <= 64, | ||
| 6198 | "RAND_TABLE_BIT may be in join_tabs[i].dependent, so we test " | ||
| 6199 | "all 64 bits."); | ||
| 6200 |
2/2✓ Branch 0 taken 205248 times.
✓ Branch 1 taken 3207 times.
|
208455 | for (uint j = 0; j < 64; j++) { |
| 6201 |
3/4✓ Branch 0 taken 300 times.
✓ Branch 1 taken 204948 times.
✓ Branch 2 taken 300 times.
✗ Branch 3 not taken.
|
205248 | if (join_tabs[i].dependent & (1ULL << j)) depends_on.add(j); |
| 6202 | } | ||
| 6203 | 3207 | } | |
| 6204 | 2711 | } | |
| 6205 | |||
| 6206 | /** | ||
| 6207 | Add to join_tab[i]->condition() "table.field IS NOT NULL" conditions | ||
| 6208 | we've inferred from ref/eq_ref access performed. | ||
| 6209 | |||
| 6210 | This function is a part of "Early NULL-values filtering for ref access" | ||
| 6211 | optimization. | ||
| 6212 | |||
| 6213 | Example of this optimization: | ||
| 6214 | For query SELECT * FROM t1,t2 WHERE t2.key=t1.field @n | ||
| 6215 | and plan " any-access(t1), ref(t2.key=t1.field) " @n | ||
| 6216 | add "t1.field IS NOT NULL" to t1's table condition. @n | ||
| 6217 | |||
| 6218 | Description of the optimization: | ||
| 6219 | |||
| 6220 | We look through equalities chosen to perform ref/eq_ref access, | ||
| 6221 | pick equalities that have form "tbl.part_of_key = othertbl.field" | ||
| 6222 | (where othertbl is a non-const table and othertbl.field may be NULL) | ||
| 6223 | and add them to conditions on corresponding tables (othertbl in this | ||
| 6224 | example). | ||
| 6225 | |||
| 6226 | Exception from that is the case when referred_tab->join != join. | ||
| 6227 | I.e. don't add NOT NULL constraints from any embedded subquery. | ||
| 6228 | Consider this query: | ||
| 6229 | @code | ||
| 6230 | SELECT A.f2 FROM t1 LEFT JOIN t2 A ON A.f2 = f1 | ||
| 6231 | WHERE A.f3=(SELECT MIN(f3) FROM t2 C WHERE A.f4 = C.f4) OR A.f3 IS NULL; | ||
| 6232 | @endcode | ||
| 6233 | Here condition A.f3 IS NOT NULL is going to be added to the WHERE | ||
| 6234 | condition of the embedding query. | ||
| 6235 | Another example: | ||
| 6236 | SELECT * FROM t10, t11 WHERE (t10.a < 10 OR t10.a IS NULL) | ||
| 6237 | AND t11.b <=> t10.b AND (t11.a = (SELECT MAX(a) FROM t12 | ||
| 6238 | WHERE t12.b = t10.a )); | ||
| 6239 | Here condition t10.a IS NOT NULL is going to be added. | ||
| 6240 | In both cases addition of NOT NULL condition will erroneously reject | ||
| 6241 | some rows of the result set. | ||
| 6242 | referred_tab->join != join constraint would disallow such additions. | ||
| 6243 | |||
| 6244 | This optimization doesn't affect the choices that ref, range, or join | ||
| 6245 | optimizer make. This was intentional because this was added after 4.1 | ||
| 6246 | was GA. | ||
| 6247 | |||
| 6248 | Implementation overview | ||
| 6249 | 1. update_ref_and_keys() accumulates info about null-rejecting | ||
| 6250 | predicates in in Key_field::null_rejecting | ||
| 6251 | 1.1 add_key_part saves these to Key_use. | ||
| 6252 | 2. create_ref_for_key copies them to TABLE_REF. | ||
| 6253 | 3. add_not_null_conds adds "x IS NOT NULL" to join_tab->m_condition of | ||
| 6254 | appropriate JOIN_TAB members. | ||
| 6255 | |||
| 6256 | @returns false on success, true on error | ||
| 6257 | */ | ||
| 6258 | |||
| 6259 | 1816536 | static bool add_not_null_conds(JOIN *join) { | |
| 6260 |
1/2✓ Branch 0 taken 1816640 times.
✗ Branch 1 not taken.
|
1816536 | DBUG_TRACE; |
| 6261 |
3/6✓ Branch 0 taken 1816640 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1816640 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1816640 times.
✗ Branch 5 not taken.
|
1816640 | ASSERT_BEST_REF_IN_JOIN_ORDER(join); |
| 6262 |
2/2✓ Branch 0 taken 6167481 times.
✓ Branch 1 taken 1816728 times.
|
7984209 | for (uint i = join->const_tables; i < join->tables; i++) { |
| 6263 | 6167481 | JOIN_TAB *const tab = join->best_ref[i]; | |
| 6264 |
4/4✓ Branch 0 taken 4234832 times.
✓ Branch 1 taken 1567356 times.
✓ Branch 2 taken 484 times.
✓ Branch 3 taken 4234347 times.
|
16204485 | if ((tab->type() != JT_REF && tab->type() != JT_EQ_REF && |
| 6265 |
6/6✓ Branch 0 taken 5802173 times.
✓ Branch 1 taken 365384 times.
✓ Branch 2 taken 516771 times.
✓ Branch 3 taken 1416470 times.
✓ Branch 4 taken 4751122 times.
✓ Branch 5 taken 1416466 times.
|
16569977 | tab->type() != JT_REF_OR_NULL) || |
| 6266 | 1933224 | tab->table()->is_nullable()) { | |
| 6267 | 4751122 | continue; | |
| 6268 | } | ||
| 6269 |
2/2✓ Branch 0 taken 1691132 times.
✓ Branch 1 taken 1416447 times.
|
3107593 | for (uint keypart = 0; keypart < tab->ref().key_parts; keypart++) { |
| 6270 |
2/2✓ Branch 0 taken 1525540 times.
✓ Branch 1 taken 165577 times.
|
1691132 | if ((tab->ref().null_rejecting & ((key_part_map)1 << keypart)) == 0) { |
| 6271 | 1561983 | continue; | |
| 6272 | } | ||
| 6273 |
1/2✓ Branch 0 taken 165587 times.
✗ Branch 1 not taken.
|
165577 | Item *const item = tab->ref().items[keypart]->real_item(); |
| 6274 |
7/8✓ Branch 0 taken 165587 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 140235 times.
✓ Branch 3 taken 25352 times.
✓ Branch 4 taken 812 times.
✓ Branch 5 taken 139423 times.
✓ Branch 6 taken 26164 times.
✓ Branch 7 taken 139423 times.
|
165587 | if (item->type() != Item::FIELD_ITEM || !item->is_nullable()) continue; |
| 6275 | 139423 | Item_field *const not_null_item = down_cast<Item_field *>(item); | |
| 6276 | 139423 | JOIN_TAB *referred_tab = not_null_item->field->table->reginfo.join_tab; | |
| 6277 | /* | ||
| 6278 | For UPDATE queries such as: | ||
| 6279 | UPDATE t1 SET t1.f2=(SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1); | ||
| 6280 | not_null_item is the t1.f1, but it's referred_tab is 0. | ||
| 6281 | */ | ||
| 6282 |
5/6✓ Branch 0 taken 139096 times.
✓ Branch 1 taken 327 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 139096 times.
✓ Branch 4 taken 327 times.
✓ Branch 5 taken 139096 times.
|
139423 | if (referred_tab == nullptr || referred_tab->join() != join) continue; |
| 6283 | /* Skip if we already have a 'not null' predicate for 'item' */ | ||
| 6284 |
3/4✓ Branch 0 taken 139096 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9952 times.
✓ Branch 3 taken 129144 times.
|
139096 | if (has_not_null_predicate(referred_tab->condition(), not_null_item)) |
| 6285 | 9952 | continue; | |
| 6286 |
2/4✓ Branch 0 taken 129144 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 129144 times.
✗ Branch 3 not taken.
|
129144 | Item *notnull = new Item_func_isnotnull(not_null_item); |
| 6287 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 129144 times.
|
129144 | if (notnull == nullptr) return true; |
| 6288 | /* | ||
| 6289 | We need to do full fix_fields() call here in order to have correct | ||
| 6290 | notnull->const_item(). This is needed e.g. by test_quick_select | ||
| 6291 | when it is called from make_join_query_block after this function is | ||
| 6292 | called. | ||
| 6293 | */ | ||
| 6294 |
2/4✓ Branch 0 taken 129144 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 129144 times.
|
129144 | if (notnull->fix_fields(join->thd, ¬null)) return true; |
| 6295 |
2/6✓ Branch 0 taken 129144 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 129144 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
129144 | DBUG_EXECUTE("where", |
| 6296 | print_where(join->thd, notnull, referred_tab->table()->alias, | ||
| 6297 | QT_ORDINARY);); | ||
| 6298 |
1/2✓ Branch 0 taken 129144 times.
✗ Branch 1 not taken.
|
129144 | referred_tab->and_with_condition(notnull); |
| 6299 | } | ||
| 6300 | } | ||
| 6301 | 1816728 | return false; | |
| 6302 | 1816728 | } | |
| 6303 | |||
| 6304 | /** | ||
| 6305 | Check all existing AND'ed predicates in 'cond' for an existing | ||
| 6306 | 'is not null 'not_null_item''-predicate. | ||
| 6307 | |||
| 6308 | A condition consisting of multiple AND'ed terms is recursively | ||
| 6309 | decomposed in the search for the specified not null predicate. | ||
| 6310 | |||
| 6311 | @param cond Condition to be checked. | ||
| 6312 | @param not_null_item The item in: 'is not null 'item'' to search for | ||
| 6313 | |||
| 6314 | @return true if 'is not null 'not_null_item'' is a predicate | ||
| 6315 | in the specified 'cond'. | ||
| 6316 | */ | ||
| 6317 | 139492 | static bool has_not_null_predicate(Item *cond, Item_field *not_null_item) { | |
| 6318 |
2/2✓ Branch 0 taken 101073 times.
✓ Branch 1 taken 38419 times.
|
139492 | if (cond == nullptr) return false; |
| 6319 |
2/2✓ Branch 0 taken 38214 times.
✓ Branch 1 taken 205 times.
|
38419 | if (cond->type() == Item::FUNC_ITEM) { |
| 6320 | 38214 | Item_func *item_func = down_cast<Item_func *>(cond); | |
| 6321 | 38214 | const Item_func::Functype func_type = item_func->functype(); | |
| 6322 |
1/2✓ Branch 0 taken 38214 times.
✗ Branch 1 not taken.
|
76428 | return (func_type == Item_func::ISNOTNULL_FUNC && |
| 6323 |
2/2✓ Branch 0 taken 9952 times.
✓ Branch 1 taken 28262 times.
|
76428 | item_func->key_item() == not_null_item); |
| 6324 |
1/2✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
|
205 | } else if (cond->type() == Item::COND_ITEM) { |
| 6325 | 205 | Item_cond *item_cond = down_cast<Item_cond *>(cond); | |
| 6326 |
1/2✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
|
205 | if (item_cond->functype() == Item_func::COND_AND_FUNC) { |
| 6327 |
1/2✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
|
205 | List_iterator<Item> li(*item_cond->argument_list()); |
| 6328 | Item *item; | ||
| 6329 |
2/2✓ Branch 0 taken 396 times.
✓ Branch 1 taken 183 times.
|
579 | while ((item = li++)) { |
| 6330 |
3/4✓ Branch 0 taken 396 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 374 times.
|
396 | if (has_not_null_predicate(item, not_null_item)) return true; |
| 6331 | } | ||
| 6332 | } | ||
| 6333 | } | ||
| 6334 | 183 | return false; | |
| 6335 | } | ||
| 6336 | |||
| 6337 | /** | ||
| 6338 | Check if given expression only uses fields covered by index @a keyno in the | ||
| 6339 | table tbl. The expression can use any fields in any other tables. | ||
| 6340 | |||
| 6341 | The expression is guaranteed not to be AND or OR - those constructs are | ||
| 6342 | handled outside of this function. | ||
| 6343 | |||
| 6344 | Restrict some function types from being pushed down to storage engine: | ||
| 6345 | a) Don't push down the triggered conditions. Nested outer joins execution | ||
| 6346 | code may need to evaluate a condition several times (both triggered and | ||
| 6347 | untriggered). | ||
| 6348 | TODO: Consider cloning the triggered condition and using the copies for: | ||
| 6349 | 1. push the first copy down, to have most restrictive index condition | ||
| 6350 | possible. | ||
| 6351 | 2. Put the second copy into tab->m_condition. | ||
| 6352 | b) Stored functions contain a statement that might start new operations (like | ||
| 6353 | DML statements) from within the storage engine. This does not work against | ||
| 6354 | all SEs. | ||
| 6355 | c) Subqueries might contain nested subqueries and involve more tables. | ||
| 6356 | TODO: ROY: CHECK THIS | ||
| 6357 | d) Do not push down internal functions of type DD_INTERNAL_FUNC. When ICP is | ||
| 6358 | enabled, pushing internal functions to storage engine for evaluation will | ||
| 6359 | open data-dictionary tables. In InnoDB storage engine this will result in | ||
| 6360 | situation like recursive latching of same page by the same thread. To avoid | ||
| 6361 | such situation, internal functions of type DD_INTERNAL_FUNC are not pushed | ||
| 6362 | to storage engine for evaluation. | ||
| 6363 | |||
| 6364 | @param item Expression to check | ||
| 6365 | @param tbl The table having the index | ||
| 6366 | @param keyno The index number | ||
| 6367 | @param other_tbls_ok true <=> Fields of other non-const tables are allowed | ||
| 6368 | |||
| 6369 | @return false if No, true if Yes | ||
| 6370 | */ | ||
| 6371 | |||
| 6372 | 20483 | bool uses_index_fields_only(Item *item, TABLE *tbl, uint keyno, | |
| 6373 | bool other_tbls_ok) { | ||
| 6374 | // Restrictions b and c. | ||
| 6375 |
6/6✓ Branch 0 taken 20471 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 152 times.
✓ Branch 3 taken 20319 times.
✓ Branch 4 taken 164 times.
✓ Branch 5 taken 20319 times.
|
20483 | if (item->has_stored_program() || item->has_subquery()) return false; |
| 6376 | |||
| 6377 | // No table fields in const items | ||
| 6378 |
2/2✓ Branch 0 taken 4704 times.
✓ Branch 1 taken 15615 times.
|
20319 | if (item->const_for_execution()) return true; |
| 6379 | |||
| 6380 | 15615 | const Item::Type item_type = item->type(); | |
| 6381 | |||
| 6382 |
4/5✓ Branch 0 taken 7864 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7638 times.
✓ Branch 3 taken 79 times.
✓ Branch 4 taken 34 times.
|
15615 | switch (item_type) { |
| 6383 | 7864 | case Item::FUNC_ITEM: { | |
| 6384 | 7864 | Item_func *item_func = (Item_func *)item; | |
| 6385 | 7864 | const Item_func::Functype func_type = item_func->functype(); | |
| 6386 | |||
| 6387 |
3/4✓ Branch 0 taken 7650 times.
✓ Branch 1 taken 214 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7650 times.
|
7864 | if (func_type == Item_func::TRIG_COND_FUNC || // Restriction a. |
| 6388 | func_type == Item_func::DD_INTERNAL_FUNC) // Restriction d. | ||
| 6389 | 214 | return false; | |
| 6390 | |||
| 6391 | /* This is a function, apply condition recursively to arguments */ | ||
| 6392 |
2/2✓ Branch 0 taken 7644 times.
✓ Branch 1 taken 6 times.
|
7650 | if (item_func->argument_count() > 0) { |
| 6393 | Item **item_end = | ||
| 6394 | 7644 | (item_func->arguments()) + item_func->argument_count(); | |
| 6395 |
2/2✓ Branch 0 taken 12601 times.
✓ Branch 1 taken 4641 times.
|
17242 | for (Item **child = item_func->arguments(); child != item_end; |
| 6396 | child++) { | ||
| 6397 |
2/2✓ Branch 0 taken 3003 times.
✓ Branch 1 taken 9598 times.
|
12601 | if (!uses_index_fields_only(*child, tbl, keyno, other_tbls_ok)) |
| 6398 | 3003 | return false; | |
| 6399 | } | ||
| 6400 | } | ||
| 6401 | 4647 | return true; | |
| 6402 | } | ||
| 6403 | ✗ | case Item::COND_ITEM: { | |
| 6404 | /* | ||
| 6405 | This is a AND/OR condition. Regular AND/OR clauses are handled by | ||
| 6406 | make_cond_for_index() which will chop off the part that can be | ||
| 6407 | checked with index. This code is for handling non-top-level AND/ORs, | ||
| 6408 | e.g. func(x AND y). | ||
| 6409 | */ | ||
| 6410 | ✗ | List_iterator<Item> li(*((Item_cond *)item)->argument_list()); | |
| 6411 | Item *cond_item; | ||
| 6412 | ✗ | while ((cond_item = li++)) { | |
| 6413 | ✗ | if (!uses_index_fields_only(cond_item, tbl, keyno, other_tbls_ok)) | |
| 6414 | ✗ | return false; | |
| 6415 | } | ||
| 6416 | ✗ | return true; | |
| 6417 | } | ||
| 6418 | 7638 | case Item::FIELD_ITEM: { | |
| 6419 | 7638 | const Item_field *item_field = down_cast<const Item_field *>(item); | |
| 6420 |
2/2✓ Branch 0 taken 236 times.
✓ Branch 1 taken 7402 times.
|
7638 | if (item_field->field->table != tbl) return other_tbls_ok; |
| 6421 | /* | ||
| 6422 | The below is probably a repetition - the first part checks the | ||
| 6423 | other two, but let's play it safe: | ||
| 6424 | */ | ||
| 6425 | 7402 | return item_field->field->part_of_key.is_set(keyno) && | |
| 6426 |
3/4✓ Branch 0 taken 4494 times.
✓ Branch 1 taken 2908 times.
✓ Branch 2 taken 4494 times.
✗ Branch 3 not taken.
|
11896 | item_field->field->type() != MYSQL_TYPE_GEOMETRY && |
| 6427 |
1/2✓ Branch 0 taken 4494 times.
✗ Branch 1 not taken.
|
11896 | item_field->field->type() != MYSQL_TYPE_BLOB; |
| 6428 | } | ||
| 6429 | 79 | case Item::REF_ITEM: | |
| 6430 | 79 | return uses_index_fields_only(item->real_item(), tbl, keyno, | |
| 6431 | 79 | other_tbls_ok); | |
| 6432 | 34 | default: | |
| 6433 | 34 | return false; /* Play it safe, don't push unknown non-const items */ | |
| 6434 | } | ||
| 6435 | } | ||
| 6436 | |||
| 6437 | /** | ||
| 6438 | Optimize semi-join nests that could be run with sj-materialization | ||
| 6439 | |||
| 6440 | @param join The join to optimize semi-join nests for | ||
| 6441 | |||
| 6442 | @details | ||
| 6443 | Optimize each of the semi-join nests that can be run with | ||
| 6444 | materialization. For each of the nests, we | ||
| 6445 | - Generate the best join order for this "sub-join" and remember it; | ||
| 6446 | - Remember the sub-join execution cost (it's part of materialization | ||
| 6447 | cost); | ||
| 6448 | - Calculate other costs that will be incurred if we decide | ||
| 6449 | to use materialization strategy for this semi-join nest. | ||
| 6450 | |||
| 6451 | All obtained information is saved and will be used by the main join | ||
| 6452 | optimization pass. | ||
| 6453 | |||
| 6454 | @return false if successful, true if error | ||
| 6455 | */ | ||
| 6456 | |||
| 6457 | 21301 | static bool optimize_semijoin_nests_for_materialization(JOIN *join) { | |
| 6458 |
1/2✓ Branch 0 taken 21301 times.
✗ Branch 1 not taken.
|
21301 | DBUG_TRACE; |
| 6459 | 21301 | Opt_trace_context *const trace = &join->thd->opt_trace; | |
| 6460 | |||
| 6461 |
7/12✓ Branch 0 taken 21301 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21301 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19904 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 19904 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 41205 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 19904 times.
✓ Branch 11 taken 21301 times.
|
41205 | for (TABLE_LIST *sj_nest : join->query_block->sj_nests) { |
| 6462 | /* As a precaution, reset pointers that were used in prior execution */ | ||
| 6463 | 19904 | sj_nest->nested_join->sjm.positions = nullptr; | |
| 6464 | |||
| 6465 | /* Calculate the cost of materialization if materialization is allowed. */ | ||
| 6466 |
2/2✓ Branch 0 taken 10138 times.
✓ Branch 1 taken 9766 times.
|
19904 | if (sj_nest->nested_join->sj_enabled_strategies & |
| 6467 | OPTIMIZER_SWITCH_MATERIALIZATION) { | ||
| 6468 | /* A semi-join nest should not contain tables marked as const */ | ||
| 6469 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10138 times.
|
10138 | assert(!(sj_nest->sj_inner_tables & join->const_table_map)); |
| 6470 | |||
| 6471 |
1/2✓ Branch 0 taken 10138 times.
✗ Branch 1 not taken.
|
10138 | Opt_trace_object trace_wrapper(trace); |
| 6472 | Opt_trace_object trace_sjmat( | ||
| 6473 |
1/2✓ Branch 0 taken 10138 times.
✗ Branch 1 not taken.
|
10138 | trace, "execution_plan_for_potential_materialization"); |
| 6474 |
1/2✓ Branch 0 taken 10138 times.
✗ Branch 1 not taken.
|
10138 | Opt_trace_array trace_sjmat_steps(trace, "steps"); |
| 6475 | /* | ||
| 6476 | Try semijoin materialization if the semijoin is classified as | ||
| 6477 | non-trivially-correlated. | ||
| 6478 | */ | ||
| 6479 |
2/2✓ Branch 0 taken 764 times.
✓ Branch 1 taken 9374 times.
|
10138 | if (sj_nest->nested_join->sj_corr_tables) continue; |
| 6480 | /* | ||
| 6481 | Check whether data types allow execution with materialization. | ||
| 6482 | */ | ||
| 6483 |
1/2✓ Branch 0 taken 9374 times.
✗ Branch 1 not taken.
|
9374 | semijoin_types_allow_materialization(sj_nest); |
| 6484 | |||
| 6485 |
2/2✓ Branch 0 taken 690 times.
✓ Branch 1 taken 8684 times.
|
9374 | if (!sj_nest->nested_join->sjm.scan_allowed && |
| 6486 |
1/2✓ Branch 0 taken 690 times.
✗ Branch 1 not taken.
|
690 | !sj_nest->nested_join->sjm.lookup_allowed) |
| 6487 | 690 | continue; | |
| 6488 | |||
| 6489 |
3/6✓ Branch 0 taken 8684 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8684 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8684 times.
|
8684 | if (Optimize_table_order(join->thd, join, sj_nest).choose_table_order()) |
| 6490 | ✗ | return true; | |
| 6491 | 8684 | const uint n_tables = my_count_bits(sj_nest->sj_inner_tables); | |
| 6492 | 8684 | calculate_materialization_costs(join, sj_nest, n_tables, | |
| 6493 |
1/2✓ Branch 0 taken 8684 times.
✗ Branch 1 not taken.
|
8684 | &sj_nest->nested_join->sjm); |
| 6494 | /* | ||
| 6495 | Cost data is in sj_nest->nested_join->sjm. We also need to save the | ||
| 6496 | plan: | ||
| 6497 | */ | ||
| 6498 | 17368 | if (!(sj_nest->nested_join->sjm.positions = | |
| 6499 |
2/4✓ Branch 0 taken 8684 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8684 times.
|
8684 | (POSITION *)join->thd->alloc(sizeof(POSITION) * n_tables))) |
| 6500 | ✗ | return true; | |
| 6501 | 8684 | memcpy(sj_nest->nested_join->sjm.positions, | |
| 6502 | 8684 | join->best_positions + join->const_tables, | |
| 6503 | 8684 | sizeof(POSITION) * n_tables); | |
| 6504 |
6/9✓ Branch 0 taken 8684 times.
✓ Branch 1 taken 1454 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8684 times.
✓ Branch 4 taken 1454 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8684 times.
✓ Branch 7 taken 1454 times.
✗ Branch 8 not taken.
|
13046 | } |
| 6505 | } | ||
| 6506 | 21301 | return false; | |
| 6507 | 21301 | } | |
| 6508 | |||
| 6509 | /* | ||
| 6510 | Check if table's Key_use elements have an eq_ref(outer_tables) candidate | ||
| 6511 | |||
| 6512 | SYNOPSIS | ||
| 6513 | find_eq_ref_candidate() | ||
| 6514 | tl Table to be checked | ||
| 6515 | sj_inner_tables Bitmap of inner tables. eq_ref(inner_table) doesn't | ||
| 6516 | count. | ||
| 6517 | |||
| 6518 | DESCRIPTION | ||
| 6519 | Check if table's Key_use elements have an eq_ref(outer_tables) candidate | ||
| 6520 | |||
| 6521 | TODO | ||
| 6522 | Check again if it is feasible to factor common parts with constant table | ||
| 6523 | search | ||
| 6524 | |||
| 6525 | RETURN | ||
| 6526 | true - There exists an eq_ref(outer-tables) candidate | ||
| 6527 | false - Otherwise | ||
| 6528 | */ | ||
| 6529 | |||
| 6530 | 30020 | static bool find_eq_ref_candidate(TABLE_LIST *tl, table_map sj_inner_tables) { | |
| 6531 | 30020 | Key_use *keyuse = tl->table->reginfo.join_tab->keyuse(); | |
| 6532 | |||
| 6533 |
2/2✓ Branch 0 taken 9187 times.
✓ Branch 1 taken 20833 times.
|
30020 | if (keyuse) { |
| 6534 | while (true) /* For each key */ | ||
| 6535 | { | ||
| 6536 | 11132 | const uint key = keyuse->key; | |
| 6537 | 11132 | KEY *const keyinfo = tl->table->key_info + key; | |
| 6538 | 11132 | key_part_map bound_parts = 0; | |
| 6539 |
2/2✓ Branch 0 taken 7682 times.
✓ Branch 1 taken 3450 times.
|
11132 | if ((keyinfo->flags & (HA_NOSAME)) == HA_NOSAME) { |
| 6540 | do /* For all equalities on all key parts */ | ||
| 6541 | { | ||
| 6542 | /* Check if this is "t.keypart = expr(outer_tables) */ | ||
| 6543 |
2/2✓ Branch 0 taken 4309 times.
✓ Branch 1 taken 5338 times.
|
9647 | if (!(keyuse->used_tables & sj_inner_tables) && |
| 6544 |
1/2✓ Branch 0 taken 4309 times.
✗ Branch 1 not taken.
|
4309 | !(keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL)) { |
| 6545 | /* | ||
| 6546 | Consider only if the resulting condition does not pass a NULL | ||
| 6547 | value through. Especially needed for a UNIQUE index on NULLable | ||
| 6548 | columns where a duplicate row is possible with NULL values. | ||
| 6549 | */ | ||
| 6550 |
5/6✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4307 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4307 times.
✓ Branch 5 taken 2 times.
|
4311 | if (keyuse->null_rejecting || !keyuse->val->is_nullable() || |
| 6551 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | !keyinfo->key_part[keyuse->keypart].field->is_nullable()) |
| 6552 | 4307 | bound_parts |= (key_part_map)1 << keyuse->keypart; | |
| 6553 | } | ||
| 6554 | 9647 | keyuse++; | |
| 6555 |
4/4✓ Branch 0 taken 5135 times.
✓ Branch 1 taken 4512 times.
✓ Branch 2 taken 1965 times.
✓ Branch 3 taken 3170 times.
|
9647 | } while (keyuse->key == key && keyuse->table_ref == tl); |
| 6556 | |||
| 6557 |
2/2✓ Branch 0 taken 3037 times.
✓ Branch 1 taken 4645 times.
|
7682 | if (bound_parts == LOWER_BITS(uint, keyinfo->user_defined_key_parts)) |
| 6558 | 3037 | return true; | |
| 6559 |
2/2✓ Branch 0 taken 3023 times.
✓ Branch 1 taken 1622 times.
|
4645 | if (keyuse->table_ref != tl) return false; |
| 6560 | } else { | ||
| 6561 | do { | ||
| 6562 | 4694 | keyuse++; | |
| 6563 |
2/2✓ Branch 0 taken 3127 times.
✓ Branch 1 taken 1567 times.
|
4694 | if (keyuse->table_ref != tl) return false; |
| 6564 |
2/2✓ Branch 0 taken 1244 times.
✓ Branch 1 taken 323 times.
|
1567 | } while (keyuse->key == key); |
| 6565 | } | ||
| 6566 | 1945 | } | |
| 6567 | } | ||
| 6568 | 20833 | return false; | |
| 6569 | } | ||
| 6570 | |||
| 6571 | /** | ||
| 6572 | Pull tables out of semi-join nests based on functional dependencies | ||
| 6573 | |||
| 6574 | @param join The join where to do the semi-join table pullout | ||
| 6575 | |||
| 6576 | @return False if successful, true if error (Out of memory) | ||
| 6577 | |||
| 6578 | @details | ||
| 6579 | Pull tables out of semi-join nests based on functional dependencies, | ||
| 6580 | ie. if a table is accessed via eq_ref(outer_tables). | ||
| 6581 | The function may be called several times, the caller is responsible | ||
| 6582 | for setting up proper key information that this function acts upon. | ||
| 6583 | |||
| 6584 | PRECONDITIONS | ||
| 6585 | When this function is called, the join may have several semi-join nests | ||
| 6586 | but it is guaranteed that one semi-join nest does not contain another. | ||
| 6587 | For functionally dependent tables to be pulled out, key information must | ||
| 6588 | have been calculated (see update_ref_and_keys()). | ||
| 6589 | |||
| 6590 | POSTCONDITIONS | ||
| 6591 | * Tables that were pulled out are removed from the semi-join nest they | ||
| 6592 | belonged to and added to the parent join nest. | ||
| 6593 | * For these tables, the used_tables and not_null_tables fields of | ||
| 6594 | the semi-join nest they belonged to will be adjusted. | ||
| 6595 | The semi-join nest is also marked as correlated, and | ||
| 6596 | sj_corr_tables and sj_depends_on are adjusted if necessary. | ||
| 6597 | * Semi-join nests' sj_inner_tables is set equal to used_tables | ||
| 6598 | |||
| 6599 | NOTE | ||
| 6600 | Table pullout may make uncorrelated subquery correlated. Consider this | ||
| 6601 | example: | ||
| 6602 | |||
| 6603 | ... WHERE oe IN (SELECT it1.primary_key WHERE p(it1, it2) ... ) | ||
| 6604 | |||
| 6605 | here table it1 can be pulled out (we have it1.primary_key=oe which gives | ||
| 6606 | us functional dependency). Once it1 is pulled out, all references to it1 | ||
| 6607 | from p(it1, it2) become references to outside of the subquery and thus | ||
| 6608 | make the subquery (i.e. its semi-join nest) correlated. | ||
| 6609 | Making the subquery (i.e. its semi-join nest) correlated prevents us from | ||
| 6610 | using Materialization or LooseScan to execute it. | ||
| 6611 | */ | ||
| 6612 | |||
| 6613 | 20542 | static bool pull_out_semijoin_tables(JOIN *join) { | |
| 6614 |
1/2✓ Branch 0 taken 20542 times.
✗ Branch 1 not taken.
|
20542 | DBUG_TRACE; |
| 6615 | |||
| 6616 |
2/4✓ Branch 0 taken 20542 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20542 times.
|
20542 | assert(!join->query_block->sj_nests.empty()); |
| 6617 | |||
| 6618 | 20542 | Opt_trace_context *const trace = &join->thd->opt_trace; | |
| 6619 |
1/2✓ Branch 0 taken 20542 times.
✗ Branch 1 not taken.
|
20542 | Opt_trace_object trace_wrapper(trace); |
| 6620 |
1/2✓ Branch 0 taken 20542 times.
✗ Branch 1 not taken.
|
20542 | Opt_trace_array trace_pullout(trace, "pulled_out_semijoin_tables"); |
| 6621 | |||
| 6622 | /* Try pulling out tables from each semi-join nest */ | ||
| 6623 |
1/2✓ Branch 0 taken 20542 times.
✗ Branch 1 not taken.
|
20542 | for (auto sj_list_it = join->query_block->sj_nests.begin(); |
| 6624 |
4/6✓ Branch 0 taken 41827 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 41827 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21285 times.
✓ Branch 5 taken 20542 times.
|
41827 | sj_list_it != join->query_block->sj_nests.end();) { |
| 6625 |
1/2✓ Branch 0 taken 21285 times.
✗ Branch 1 not taken.
|
21285 | TABLE_LIST *sj_nest = *sj_list_it; |
| 6626 |
2/2✓ Branch 0 taken 340 times.
✓ Branch 1 taken 20945 times.
|
21285 | if (sj_nest->is_aj_nest()) { |
| 6627 |
1/2✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
|
340 | ++sj_list_it; |
| 6628 | 340 | continue; | |
| 6629 | } | ||
| 6630 | 20945 | table_map pulled_tables = 0; | |
| 6631 | /* | ||
| 6632 | Calculate set of tables within this semi-join nest that have | ||
| 6633 | other dependent tables. They cannot be pulled out. For example, with | ||
| 6634 | t1 SEMIJOIN (t2 LEFT JOIN t3 ON ...) ON t1.a=t2.pk, | ||
| 6635 | t2 cannot be pulled out because t3 depends on it. | ||
| 6636 | */ | ||
| 6637 | 20945 | table_map dep_tables = 0; | |
| 6638 |
7/12✓ Branch 0 taken 20945 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20945 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 38515 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 38515 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 59460 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 38515 times.
✓ Branch 11 taken 20945 times.
|
59460 | for (TABLE_LIST *tbl : sj_nest->nested_join->join_list) { |
| 6639 |
2/2✓ Branch 0 taken 7218 times.
✓ Branch 1 taken 31297 times.
|
38515 | if (tbl->dep_tables & sj_nest->nested_join->used_tables) |
| 6640 | 7218 | dep_tables |= tbl->dep_tables; | |
| 6641 | } | ||
| 6642 | /* | ||
| 6643 | Find which tables we can pull out based on key dependency data. | ||
| 6644 | Note that pulling one table out can allow us to pull out some | ||
| 6645 | other tables too. | ||
| 6646 | */ | ||
| 6647 | bool pulled_a_table; | ||
| 6648 |
2/2✓ Branch 0 taken 2927 times.
✓ Branch 1 taken 20945 times.
|
23872 | do { |
| 6649 | 23872 | pulled_a_table = false; | |
| 6650 |
7/12✓ Branch 0 taken 23872 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23872 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 42044 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 42044 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 65916 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 42044 times.
✓ Branch 11 taken 23872 times.
|
65916 | for (TABLE_LIST *tbl : sj_nest->nested_join->join_list) { |
| 6651 |
6/6✓ Branch 0 taken 41815 times.
✓ Branch 1 taken 229 times.
✓ Branch 2 taken 38673 times.
✓ Branch 3 taken 3142 times.
✓ Branch 4 taken 30020 times.
✓ Branch 5 taken 12024 times.
|
80717 | if (tbl->table && !(pulled_tables & tbl->map()) && |
| 6652 |
2/2✓ Branch 0 taken 30020 times.
✓ Branch 1 taken 8653 times.
|
38673 | !(dep_tables & tbl->map())) { |
| 6653 |
2/2✓ Branch 0 taken 3037 times.
✓ Branch 1 taken 26983 times.
|
30020 | if (find_eq_ref_candidate( |
| 6654 | 30020 | tbl, sj_nest->nested_join->used_tables & ~pulled_tables)) { | |
| 6655 | 3037 | pulled_a_table = true; | |
| 6656 | 3037 | pulled_tables |= tbl->map(); | |
| 6657 |
3/6✓ Branch 0 taken 3037 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3037 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3037 times.
✗ Branch 5 not taken.
|
3037 | Opt_trace_object(trace).add_utf8_table(tbl).add( |
| 6658 | "functionally_dependent", true); | ||
| 6659 | /* | ||
| 6660 | Pulling a table out of uncorrelated subquery in general makes | ||
| 6661 | it correlated. See the NOTE to this function. | ||
| 6662 | */ | ||
| 6663 | 3037 | sj_nest->nested_join->sj_corr_tables |= tbl->map(); | |
| 6664 | 3037 | sj_nest->nested_join->sj_depends_on |= tbl->map(); | |
| 6665 | } | ||
| 6666 | } | ||
| 6667 | } | ||
| 6668 | } while (pulled_a_table); | ||
| 6669 | |||
| 6670 | /* | ||
| 6671 | Move the pulled out TABLE_LIST elements to the parents. | ||
| 6672 | */ | ||
| 6673 | 20945 | sj_nest->nested_join->used_tables &= ~pulled_tables; | |
| 6674 | 20945 | sj_nest->nested_join->not_null_tables &= ~pulled_tables; | |
| 6675 | |||
| 6676 | /* sj_inner_tables is a copy of nested_join->used_tables */ | ||
| 6677 | 20945 | sj_nest->sj_inner_tables = sj_nest->nested_join->used_tables; | |
| 6678 | |||
| 6679 | 20945 | bool remove = false; | |
| 6680 |
2/2✓ Branch 0 taken 2834 times.
✓ Branch 1 taken 18111 times.
|
20945 | if (pulled_tables) { |
| 6681 | 2834 | mem_root_deque<TABLE_LIST *> *upper_join_list = | |
| 6682 | 2834 | (sj_nest->embedding != nullptr) | |
| 6683 |
2/2✓ Branch 0 taken 90 times.
✓ Branch 1 taken 2744 times.
|
2834 | ? &sj_nest->embedding->nested_join->join_list |
| 6684 | 2744 | : &join->query_block->top_join_list; | |
| 6685 | |||
| 6686 |
1/2✓ Branch 0 taken 2834 times.
✗ Branch 1 not taken.
|
2834 | Prepared_stmt_arena_holder ps_arena_holder(join->thd); |
| 6687 | |||
| 6688 |
1/2✓ Branch 0 taken 2834 times.
✗ Branch 1 not taken.
|
2834 | for (auto child_li = sj_nest->nested_join->join_list.begin(); |
| 6689 |
4/6✓ Branch 0 taken 6153 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6153 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3319 times.
✓ Branch 5 taken 2834 times.
|
6153 | child_li != sj_nest->nested_join->join_list.end();) { |
| 6690 |
1/2✓ Branch 0 taken 3319 times.
✗ Branch 1 not taken.
|
3319 | TABLE_LIST *tbl = *child_li; |
| 6691 |
5/6✓ Branch 0 taken 3319 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3037 times.
✓ Branch 3 taken 282 times.
✓ Branch 4 taken 3037 times.
✓ Branch 5 taken 282 times.
|
3319 | if (tbl->table && !(sj_nest->nested_join->used_tables & tbl->map())) { |
| 6692 | /* | ||
| 6693 | Pull the table up in the same way as simplify_joins() does: | ||
| 6694 | update join_list and embedding pointers but keep next[_local] | ||
| 6695 | pointers. | ||
| 6696 | */ | ||
| 6697 |
1/2✓ Branch 0 taken 3037 times.
✗ Branch 1 not taken.
|
3037 | child_li = sj_nest->nested_join->join_list.erase(child_li); |
| 6698 | |||
| 6699 |
1/2✓ Branch 0 taken 3037 times.
✗ Branch 1 not taken.
|
3037 | upper_join_list->push_back(tbl); |
| 6700 | |||
| 6701 | 3037 | tbl->join_list = upper_join_list; | |
| 6702 | 3037 | tbl->embedding = sj_nest->embedding; | |
| 6703 | } else { | ||
| 6704 |
1/2✓ Branch 0 taken 282 times.
✗ Branch 1 not taken.
|
282 | ++child_li; |
| 6705 | } | ||
| 6706 | } | ||
| 6707 | |||
| 6708 | /* Remove the sj-nest itself if we've removed everything from it */ | ||
| 6709 |
2/2✓ Branch 0 taken 2556 times.
✓ Branch 1 taken 278 times.
|
2834 | if (!sj_nest->nested_join->used_tables) { |
| 6710 |
4/8✓ Branch 0 taken 2556 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2556 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2556 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2556 times.
✗ Branch 7 not taken.
|
2556 | upper_join_list->erase(std::find(upper_join_list->begin(), |
| 6711 | upper_join_list->end(), sj_nest)); | ||
| 6712 | /* Also remove it from the list of SJ-nests: */ | ||
| 6713 | 2556 | remove = true; | |
| 6714 | } | ||
| 6715 | 2834 | } | |
| 6716 | |||
| 6717 |
2/2✓ Branch 0 taken 2556 times.
✓ Branch 1 taken 18389 times.
|
20945 | if (remove) { |
| 6718 |
1/2✓ Branch 0 taken 2556 times.
✗ Branch 1 not taken.
|
2556 | sj_list_it = join->query_block->sj_nests.erase(sj_list_it); |
| 6719 | } else { | ||
| 6720 |
1/2✓ Branch 0 taken 18389 times.
✗ Branch 1 not taken.
|
18389 | ++sj_list_it; |
| 6721 | } | ||
| 6722 | } | ||
| 6723 | 20542 | return false; | |
| 6724 | 20542 | } | |
| 6725 | |||
| 6726 | /* Values in optimize */ | ||
| 6727 | #define KEY_OPTIMIZE_EXISTS 1 | ||
| 6728 | #define KEY_OPTIMIZE_REF_OR_NULL 2 | ||
| 6729 | |||
| 6730 | /** | ||
| 6731 | Merge new key definitions to old ones, remove those not used in both. | ||
| 6732 | |||
| 6733 | This is called for OR between different levels. | ||
| 6734 | |||
| 6735 | To be able to do 'ref_or_null' we merge a comparison of a column | ||
| 6736 | and 'column IS NULL' to one test. This is useful for sub select queries | ||
| 6737 | that are internally transformed to something like:. | ||
| 6738 | |||
| 6739 | @code | ||
| 6740 | SELECT * FROM t1 WHERE t1.key=outer_ref_field or t1.key IS NULL | ||
| 6741 | @endcode | ||
| 6742 | |||
| 6743 | Key_field::null_rejecting is processed as follows: @n | ||
| 6744 | result has null_rejecting=true if it is set for both ORed references. | ||
| 6745 | for example: | ||
| 6746 | - (t2.key = t1.field OR t2.key = t1.field) -> null_rejecting=true | ||
| 6747 | - (t2.key = t1.field OR t2.key <=> t1.field) -> null_rejecting=false | ||
| 6748 | |||
| 6749 | @todo | ||
| 6750 | The result of this is that we're missing some 'ref' accesses. | ||
| 6751 | OptimizerTeam: Fix this | ||
| 6752 | */ | ||
| 6753 | |||
| 6754 | 41494 | static Key_field *merge_key_fields(Key_field *start, Key_field *new_fields, | |
| 6755 | Key_field *end, uint and_level) { | ||
| 6756 |
2/2✓ Branch 0 taken 37846 times.
✓ Branch 1 taken 3648 times.
|
41494 | if (start == new_fields) return start; // Impossible or |
| 6757 |
2/2✓ Branch 0 taken 349 times.
✓ Branch 1 taken 3299 times.
|
3648 | if (new_fields == end) return start; // No new fields, skip all |
| 6758 | |||
| 6759 | 3299 | Key_field *first_free = new_fields; | |
| 6760 | |||
| 6761 | /* Mark all found fields in old array */ | ||
| 6762 |
2/2✓ Branch 0 taken 4254 times.
✓ Branch 1 taken 3299 times.
|
7553 | for (; new_fields != end; new_fields++) { |
| 6763 | 4254 | const Field *const new_field = new_fields->item_field->field; | |
| 6764 | |||
| 6765 |
2/2✓ Branch 0 taken 33057 times.
✓ Branch 1 taken 2661 times.
|
35718 | for (Key_field *old = start; old != first_free; old++) { |
| 6766 | 33057 | const Field *const old_field = old->item_field->field; | |
| 6767 | |||
| 6768 | /* | ||
| 6769 | Check that the Field objects are the same, as we may have several | ||
| 6770 | Item_field objects pointing to the same Field: | ||
| 6771 | */ | ||
| 6772 |
2/2✓ Branch 0 taken 6742 times.
✓ Branch 1 taken 26315 times.
|
33057 | if (old_field == new_field) { |
| 6773 | /* | ||
| 6774 | NOTE: below const_item() call really works as "!used_tables()", i.e. | ||
| 6775 | it can return false where it is feasible to make it return true. | ||
| 6776 | |||
| 6777 | The cause is as follows: Some of the tables are already known to be | ||
| 6778 | const tables (the detection code is in JOIN::make_join_plan(), | ||
| 6779 | above the update_ref_and_keys() call), but we didn't propagate | ||
| 6780 | information about this: TABLE::const_table is not set to true, and | ||
| 6781 | Item::update_used_tables() hasn't been called for each item. | ||
| 6782 | The result of this is that we're missing some 'ref' accesses. | ||
| 6783 | TODO: OptimizerTeam: Fix this | ||
| 6784 | */ | ||
| 6785 |
2/2✓ Branch 0 taken 3748 times.
✓ Branch 1 taken 2994 times.
|
6742 | if (!new_fields->val->const_item()) { |
| 6786 | /* | ||
| 6787 | If the value matches, we can use the key reference. | ||
| 6788 | If not, we keep it until we have examined all new values | ||
| 6789 | */ | ||
| 6790 |
2/2✓ Branch 0 taken 534 times.
✓ Branch 1 taken 3214 times.
|
3748 | if (old->val->eq(new_fields->val, old_field->binary())) { |
| 6791 | 534 | old->level = and_level; | |
| 6792 | 534 | old->optimize = | |
| 6793 | 534 | ((old->optimize & new_fields->optimize & KEY_OPTIMIZE_EXISTS) | | |
| 6794 | 534 | ((old->optimize | new_fields->optimize) & | |
| 6795 | KEY_OPTIMIZE_REF_OR_NULL)); | ||
| 6796 | 534 | old->null_rejecting = | |
| 6797 |
2/4✓ Branch 0 taken 534 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 534 times.
✗ Branch 3 not taken.
|
534 | (old->null_rejecting && new_fields->null_rejecting); |
| 6798 | } | ||
| 6799 |
4/6✓ Branch 0 taken 2994 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2994 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 294 times.
✓ Branch 5 taken 2700 times.
|
5988 | } else if (old->eq_func && new_fields->eq_func && |
| 6800 |
2/2✓ Branch 0 taken 294 times.
✓ Branch 1 taken 2700 times.
|
2994 | old->val->eq_by_collation(new_fields->val, |
| 6801 | 2994 | old_field->binary(), | |
| 6802 | 2994 | old_field->charset())) { | |
| 6803 | 294 | old->level = and_level; | |
| 6804 | 294 | old->optimize = | |
| 6805 | 294 | ((old->optimize & new_fields->optimize & KEY_OPTIMIZE_EXISTS) | | |
| 6806 | 294 | ((old->optimize | new_fields->optimize) & | |
| 6807 | KEY_OPTIMIZE_REF_OR_NULL)); | ||
| 6808 | 294 | old->null_rejecting = | |
| 6809 |
3/4✓ Branch 0 taken 262 times.
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 262 times.
✗ Branch 3 not taken.
|
294 | (old->null_rejecting && new_fields->null_rejecting); |
| 6810 |
4/6✓ Branch 0 taken 2700 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2700 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1007 times.
✓ Branch 5 taken 1693 times.
|
5400 | } else if (old->eq_func && new_fields->eq_func && |
| 6811 |
4/4✓ Branch 0 taken 1970 times.
✓ Branch 1 taken 730 times.
✓ Branch 2 taken 1855 times.
✓ Branch 3 taken 115 times.
|
2700 | ((old->val->const_item() && old->val->is_null()) || |
| 6812 |
2/2✓ Branch 0 taken 892 times.
✓ Branch 1 taken 1693 times.
|
2585 | new_fields->val->is_null())) { |
| 6813 | /* field = expression OR field IS NULL */ | ||
| 6814 | 1007 | old->level = and_level; | |
| 6815 | 1007 | old->optimize = KEY_OPTIMIZE_REF_OR_NULL; | |
| 6816 | /* | ||
| 6817 | Remember the NOT NULL value unless the value does not depend | ||
| 6818 | on other tables. | ||
| 6819 | */ | ||
| 6820 |
6/6✓ Branch 0 taken 300 times.
✓ Branch 1 taken 707 times.
✓ Branch 2 taken 115 times.
✓ Branch 3 taken 185 times.
✓ Branch 4 taken 115 times.
✓ Branch 5 taken 892 times.
|
1007 | if (!old->val->used_tables() && old->val->is_null()) |
| 6821 | 115 | old->val = new_fields->val; | |
| 6822 | /* The referred expression can be NULL: */ | ||
| 6823 | 1007 | old->null_rejecting = false; | |
| 6824 | } else { | ||
| 6825 | /* | ||
| 6826 | We are comparing two different const. In this case we can't | ||
| 6827 | use a key-lookup on this so it's better to remove the value | ||
| 6828 | and let the range optimizer handle it | ||
| 6829 | */ | ||
| 6830 |
2/2✓ Branch 0 taken 1593 times.
✓ Branch 1 taken 100 times.
|
1693 | if (old == --first_free) // If last item |
| 6831 | 1593 | break; | |
| 6832 | 100 | *old = *first_free; // Remove old value | |
| 6833 | 100 | old--; // Retry this value | |
| 6834 | } | ||
| 6835 | } | ||
| 6836 | } | ||
| 6837 | } | ||
| 6838 | /* Remove all not used items */ | ||
| 6839 |
2/2✓ Branch 0 taken 2645 times.
✓ Branch 1 taken 2687 times.
|
5332 | for (Key_field *old = start; old != first_free;) { |
| 6840 |
2/2✓ Branch 0 taken 885 times.
✓ Branch 1 taken 1760 times.
|
2645 | if (old->level != and_level) { // Not used in all levels |
| 6841 |
2/2✓ Branch 0 taken 612 times.
✓ Branch 1 taken 273 times.
|
885 | if (old == --first_free) break; |
| 6842 | 273 | *old = *first_free; // Remove old value | |
| 6843 | 273 | continue; | |
| 6844 | } | ||
| 6845 | 1760 | old++; | |
| 6846 | } | ||
| 6847 | 3299 | return first_free; | |
| 6848 | } | ||
| 6849 | |||
| 6850 | /** | ||
| 6851 | Given a field, return its index in semi-join's select list, or UINT_MAX | ||
| 6852 | |||
| 6853 | @param item_field Field to be looked up in select list | ||
| 6854 | |||
| 6855 | @retval =UINT_MAX Field is not from a semijoin-transformed subquery | ||
| 6856 | @retval <UINT_MAX Index in select list of subquery | ||
| 6857 | |||
| 6858 | @details | ||
| 6859 | Given a field, find its table; then see if the table is within a | ||
| 6860 | semi-join nest and if the field was in select list of the subquery | ||
| 6861 | (if subquery was part of a quantified comparison predicate), or | ||
| 6862 | the field was a result of subquery decorrelation. | ||
| 6863 | If it was, then return the field's index in the select list. | ||
| 6864 | The value is used by LooseScan strategy. | ||
| 6865 | */ | ||
| 6866 | |||
| 6867 | 4475135 | static uint get_semi_join_select_list_index(Item_field *item_field) { | |
| 6868 | 4475135 | TABLE_LIST *emb_sj_nest = item_field->table_ref->embedding; | |
| 6869 |
6/6✓ Branch 0 taken 24216 times.
✓ Branch 1 taken 4450919 times.
✓ Branch 2 taken 21415 times.
✓ Branch 3 taken 2801 times.
✓ Branch 4 taken 21415 times.
✓ Branch 5 taken 4453720 times.
|
4475135 | if (emb_sj_nest && emb_sj_nest->is_sj_or_aj_nest()) { |
| 6870 | 21415 | const mem_root_deque<Item *> &items = | |
| 6871 | 21415 | emb_sj_nest->nested_join->sj_inner_exprs; | |
| 6872 |
2/2✓ Branch 0 taken 22522 times.
✓ Branch 1 taken 15667 times.
|
38189 | for (size_t i = 0; i < items.size(); i++) { |
| 6873 | 22522 | const Item *sel_item = items[i]; | |
| 6874 |
4/4✓ Branch 0 taken 10187 times.
✓ Branch 1 taken 12333 times.
✓ Branch 2 taken 5746 times.
✓ Branch 3 taken 16774 times.
|
32707 | if (sel_item->type() == Item::FIELD_ITEM && |
| 6875 |
2/2✓ Branch 0 taken 5746 times.
✓ Branch 1 taken 4441 times.
|
10187 | down_cast<const Item_field *>(sel_item)->field->eq(item_field->field)) |
| 6876 | 5746 | return i; | |
| 6877 | } | ||
| 6878 | } | ||
| 6879 | 4469387 | return UINT_MAX; | |
| 6880 | } | ||
| 6881 | |||
| 6882 | /** | ||
| 6883 | @brief | ||
| 6884 | If EXPLAIN or if the --safe-updates option is enabled, add a warning that an | ||
| 6885 | index cannot be used for ref access. | ||
| 6886 | |||
| 6887 | @details | ||
| 6888 | If EXPLAIN or if the --safe-updates option is enabled, add a warning for each | ||
| 6889 | index that cannot be used for ref access due to either type conversion or | ||
| 6890 | different collations on the field used for comparison | ||
| 6891 | |||
| 6892 | Example type conversion (char compared to int): | ||
| 6893 | |||
| 6894 | CREATE TABLE t1 (url char(1) PRIMARY KEY); | ||
| 6895 | SELECT * FROM t1 WHERE url=1; | ||
| 6896 | |||
| 6897 | Example different collations (danish vs german2): | ||
| 6898 | |||
| 6899 | CREATE TABLE t1 (url char(1) PRIMARY KEY) collate latin1_danish_ci; | ||
| 6900 | SELECT * FROM t1 WHERE url='1' collate latin1_german2_ci; | ||
| 6901 | |||
| 6902 | @param thd Thread for the connection that submitted the query | ||
| 6903 | @param field Field used in comparison | ||
| 6904 | @param cant_use_index Indexes that cannot be used for lookup | ||
| 6905 | */ | ||
| 6906 | 2042 | static void warn_index_not_applicable(THD *thd, const Field *field, | |
| 6907 | const Key_map cant_use_index) { | ||
| 6908 |
1/2✓ Branch 0 taken 2042 times.
✗ Branch 1 not taken.
|
2042 | Functional_index_error_handler functional_index_error_handler(field, thd); |
| 6909 | |||
| 6910 |
4/4✓ Branch 0 taken 1519 times.
✓ Branch 1 taken 523 times.
✓ Branch 2 taken 526 times.
✓ Branch 3 taken 1516 times.
|
3561 | if (thd->lex->is_explain() || |
| 6911 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1516 times.
|
1519 | thd->variables.option_bits & OPTION_SAFE_UPDATES) |
| 6912 |
2/2✓ Branch 0 taken 611 times.
✓ Branch 1 taken 526 times.
|
1137 | for (uint j = 0; j < field->table->s->keys; j++) |
| 6913 |
2/2✓ Branch 0 taken 517 times.
✓ Branch 1 taken 94 times.
|
611 | if (cant_use_index.is_set(j)) |
| 6914 |
1/2✓ Branch 0 taken 517 times.
✗ Branch 1 not taken.
|
517 | push_warning_printf(thd, Sql_condition::SL_WARNING, |
| 6915 | ER_WARN_INDEX_NOT_APPLICABLE, | ||
| 6916 | ER_THD(thd, ER_WARN_INDEX_NOT_APPLICABLE), "ref", | ||
| 6917 |
1/2✓ Branch 0 taken 517 times.
✗ Branch 1 not taken.
|
517 | field->table->key_info[j].name, field->field_name); |
| 6918 | 2042 | } | |
| 6919 | |||
| 6920 | /** | ||
| 6921 | Add a possible key to array of possible keys if it's usable as a key | ||
| 6922 | |||
| 6923 | @param [in,out] key_fields Used as an input parameter in the sense that it is | ||
| 6924 | a pointer to a pointer to a memory area where an array of Key_field objects | ||
| 6925 | will stored. It is used as an out parameter in the sense that the pointer will | ||
| 6926 | be updated to point beyond the last Key_field written. | ||
| 6927 | |||
| 6928 | @param thd session context | ||
| 6929 | @param and_level And level, to be stored in Key_field | ||
| 6930 | @param cond Condition predicate | ||
| 6931 | @param item_field Field used in comparison | ||
| 6932 | @param eq_func True if we used =, <=> or IS NULL | ||
| 6933 | @param value Array of values used for comparison with field | ||
| 6934 | @param num_values Number of elements in the array of values | ||
| 6935 | @param usable_tables Tables which can be used for key optimization | ||
| 6936 | @param sargables IN/OUT Array of found sargable candidates. | ||
| 6937 | Will be ignored in case eq_func is true. | ||
| 6938 | |||
| 6939 | @note | ||
| 6940 | If we are doing a NOT NULL comparison on a NOT NULL field in a outer join | ||
| 6941 | table, we store this to be able to do not exists optimization later. | ||
| 6942 | |||
| 6943 | |||
| 6944 | @returns false if success, true if error | ||
| 6945 | */ | ||
| 6946 | |||
| 6947 | 6797105 | static bool add_key_field(THD *thd, Key_field **key_fields, uint and_level, | |
| 6948 | Item_func *cond, Item_field *item_field, bool eq_func, | ||
| 6949 | Item **value, uint num_values, | ||
| 6950 | table_map usable_tables, SARGABLE_PARAM **sargables) { | ||
| 6951 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6797196 times.
|
6797105 | assert(cond->is_bool_func()); |
| 6952 |
3/4✓ Branch 0 taken 601143 times.
✓ Branch 1 taken 6196053 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 601143 times.
|
6797196 | assert(eq_func || sargables); |
| 6953 |
47/48✓ Branch 0 taken 6562678 times.
✓ Branch 1 taken 234513 times.
✓ Branch 2 taken 6374698 times.
✓ Branch 3 taken 187986 times.
✓ Branch 4 taken 6353512 times.
✓ Branch 5 taken 21221 times.
✓ Branch 6 taken 6343727 times.
✓ Branch 7 taken 9776 times.
✓ Branch 8 taken 6337734 times.
✓ Branch 9 taken 5940 times.
✓ Branch 10 taken 6332287 times.
✓ Branch 11 taken 5430 times.
✓ Branch 12 taken 392171 times.
✓ Branch 13 taken 5940100 times.
✓ Branch 14 taken 389532 times.
✓ Branch 15 taken 2639 times.
✓ Branch 16 taken 193861 times.
✓ Branch 17 taken 195671 times.
✓ Branch 18 taken 176379 times.
✓ Branch 19 taken 17482 times.
✓ Branch 20 taken 168157 times.
✓ Branch 21 taken 8222 times.
✓ Branch 22 taken 146865 times.
✓ Branch 23 taken 21292 times.
✓ Branch 24 taken 1162 times.
✓ Branch 25 taken 145703 times.
✓ Branch 26 taken 721 times.
✓ Branch 27 taken 441 times.
✓ Branch 28 taken 639 times.
✓ Branch 29 taken 82 times.
✓ Branch 30 taken 454 times.
✓ Branch 31 taken 185 times.
✓ Branch 32 taken 336 times.
✓ Branch 33 taken 118 times.
✓ Branch 34 taken 253 times.
✓ Branch 35 taken 83 times.
✓ Branch 36 taken 194 times.
✓ Branch 37 taken 59 times.
✓ Branch 38 taken 186 times.
✓ Branch 39 taken 8 times.
✓ Branch 40 taken 176 times.
✓ Branch 41 taken 10 times.
✓ Branch 42 taken 108 times.
✓ Branch 43 taken 68 times.
✓ Branch 44 taken 31 times.
✓ Branch 45 taken 77 times.
✓ Branch 46 taken 44 times.
✗ Branch 47 not taken.
|
6797196 | assert(cond->functype() == Item_func::EQ_FUNC || |
| 6954 | cond->functype() == Item_func::NE_FUNC || | ||
| 6955 | cond->functype() == Item_func::GT_FUNC || | ||
| 6956 | cond->functype() == Item_func::LT_FUNC || | ||
| 6957 | cond->functype() == Item_func::GE_FUNC || | ||
| 6958 | cond->functype() == Item_func::LE_FUNC || | ||
| 6959 | cond->functype() == Item_func::MULT_EQUAL_FUNC || | ||
| 6960 | cond->functype() == Item_func::EQUAL_FUNC || | ||
| 6961 | cond->functype() == Item_func::LIKE_FUNC || | ||
| 6962 | cond->functype() == Item_func::ISNULL_FUNC || | ||
| 6963 | cond->functype() == Item_func::ISNOTNULL_FUNC || | ||
| 6964 | cond->functype() == Item_func::BETWEEN || | ||
| 6965 | cond->functype() == Item_func::IN_FUNC || | ||
| 6966 | cond->functype() == Item_func::MEMBER_OF_FUNC || | ||
| 6967 | cond->functype() == Item_func::SP_EQUALS_FUNC || | ||
| 6968 | cond->functype() == Item_func::SP_WITHIN_FUNC || | ||
| 6969 | cond->functype() == Item_func::SP_CONTAINS_FUNC || | ||
| 6970 | cond->functype() == Item_func::SP_INTERSECTS_FUNC || | ||
| 6971 | cond->functype() == Item_func::SP_DISJOINT_FUNC || | ||
| 6972 | cond->functype() == Item_func::SP_COVERS_FUNC || | ||
| 6973 | cond->functype() == Item_func::SP_COVEREDBY_FUNC || | ||
| 6974 | cond->functype() == Item_func::SP_OVERLAPS_FUNC || | ||
| 6975 | cond->functype() == Item_func::SP_TOUCHES_FUNC || | ||
| 6976 | cond->functype() == Item_func::SP_CROSSES_FUNC); | ||
| 6977 | |||
| 6978 | 6797093 | Field *const field = item_field->field; | |
| 6979 | 6797093 | TABLE_LIST *const tl = item_field->table_ref; | |
| 6980 | |||
| 6981 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6797093 times.
|
6797093 | if (tl->table->reginfo.join_tab == nullptr) { |
| 6982 | /* | ||
| 6983 | Due to a bug in IN-to-EXISTS (grep for real_item() in item_subselect.cc | ||
| 6984 | for more info), an index over a field from an outer query might be | ||
| 6985 | considered here, which is incorrect. Their query has been fully | ||
| 6986 | optimized already so their reginfo.join_tab is NULL and we reject them. | ||
| 6987 | */ | ||
| 6988 | ✗ | return false; | |
| 6989 | } | ||
| 6990 | |||
| 6991 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6797101 times.
|
6797093 | DBUG_PRINT("info", ("add_key_field for field %s", field->field_name)); |
| 6992 | 6797117 | uint exists_optimize = 0; | |
| 6993 |
6/6✓ Branch 0 taken 6797116 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2828 times.
✓ Branch 3 taken 6794283 times.
✓ Branch 4 taken 2508 times.
✓ Branch 5 taken 6794604 times.
|
6799945 | if (!tl->derived_keys_ready && tl->uses_materialization() && |
| 6994 |
2/2✓ Branch 0 taken 2508 times.
✓ Branch 1 taken 320 times.
|
2828 | !tl->table->is_created()) { |
| 6995 | bool allocated; | ||
| 6996 |
2/4✓ Branch 0 taken 2508 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2508 times.
|
2508 | if (tl->update_derived_keys(thd, field, value, num_values, &allocated)) |
| 6997 | 87 | return true; | |
| 6998 |
2/2✓ Branch 0 taken 87 times.
✓ Branch 1 taken 2421 times.
|
2508 | if (!allocated) return false; |
| 6999 | } | ||
| 7000 |
2/2✓ Branch 0 taken 1174432 times.
✓ Branch 1 taken 5622514 times.
|
6797025 | if (!field->is_flag_set(PART_KEY_FLAG)) { |
| 7001 | // Don't remove column IS NULL on a LEFT JOIN table | ||
| 7002 |
2/2✓ Branch 0 taken 11388 times.
✓ Branch 1 taken 1022517 times.
|
1033905 | if (!eq_func || (*value)->type() != Item::NULL_ITEM || |
| 7003 |
8/8✓ Branch 0 taken 1033905 times.
✓ Branch 1 taken 140527 times.
✓ Branch 2 taken 893 times.
✓ Branch 3 taken 10495 times.
✓ Branch 4 taken 717 times.
✓ Branch 5 taken 203 times.
✓ Branch 6 taken 1174256 times.
✓ Branch 7 taken 203 times.
|
2208337 | !tl->table->is_nullable() || field->is_nullable()) |
| 7004 | 1174256 | return false; // Not a key. Skip it | |
| 7005 | 203 | exists_optimize = KEY_OPTIMIZE_EXISTS; | |
| 7006 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
|
203 | assert(num_values == 1); |
| 7007 | } else { | ||
| 7008 | 5622514 | table_map used_tables = 0; | |
| 7009 | 5622514 | bool optimizable = false; | |
| 7010 |
2/2✓ Branch 0 taken 5980549 times.
✓ Branch 1 taken 5622588 times.
|
11603137 | for (uint i = 0; i < num_values; i++) { |
| 7011 | 5980549 | used_tables |= (value[i])->used_tables(); | |
| 7012 |
2/2✓ Branch 0 taken 5973300 times.
✓ Branch 1 taken 7323 times.
|
5980594 | if (!((value[i])->used_tables() & (tl->map() | RAND_TABLE_BIT))) |
| 7013 | 5973300 | optimizable = true; | |
| 7014 | } | ||
| 7015 |
2/2✓ Branch 0 taken 7240 times.
✓ Branch 1 taken 5615348 times.
|
5622588 | if (!optimizable) return false; |
| 7016 |
2/2✓ Branch 0 taken 680266 times.
✓ Branch 1 taken 4935070 times.
|
5615348 | if (!(usable_tables & tl->map())) { |
| 7017 |
2/2✓ Branch 0 taken 2013 times.
✓ Branch 1 taken 677139 times.
|
679155 | if (!eq_func || (*value)->type() != Item::NULL_ITEM || |
| 7018 |
8/8✓ Branch 0 taken 679155 times.
✓ Branch 1 taken 1111 times.
✓ Branch 2 taken 1998 times.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 1836 times.
✓ Branch 5 taken 165 times.
✓ Branch 6 taken 680103 times.
✓ Branch 7 taken 163 times.
|
1359418 | !tl->table->is_nullable() || field->is_nullable()) |
| 7019 | 680103 | return false; // Can't use left join optimize | |
| 7020 | 163 | exists_optimize = KEY_OPTIMIZE_EXISTS; | |
| 7021 | } else { | ||
| 7022 | 4935070 | JOIN_TAB *stat = tl->table->reginfo.join_tab; | |
| 7023 | 4935070 | Key_map possible_keys = field->key_start; | |
| 7024 | 4935070 | possible_keys.intersect(tl->table->keys_in_use_for_query); | |
| 7025 | 4935056 | stat[0].keys().merge(possible_keys); // Add possible keys | |
| 7026 | |||
| 7027 | /* | ||
| 7028 | Save the following cases: | ||
| 7029 | Field op constant | ||
| 7030 | Field LIKE constant where constant doesn't start with a wildcard | ||
| 7031 | Field = field2 where field2 is in a different table | ||
| 7032 | Field op formula | ||
| 7033 | Field IS NULL | ||
| 7034 | Field IS NOT NULL | ||
| 7035 | Field BETWEEN ... | ||
| 7036 | Field IN ... | ||
| 7037 | */ | ||
| 7038 | 4935081 | stat[0].key_dependent |= used_tables; | |
| 7039 | |||
| 7040 | 4935081 | bool is_const = true; | |
| 7041 |
2/2✓ Branch 0 taken 5292895 times.
✓ Branch 1 taken 1134786 times.
|
6427681 | for (uint i = 0; i < num_values; i++) { |
| 7042 |
3/4✓ Branch 0 taken 5292945 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3800345 times.
✓ Branch 3 taken 1492600 times.
|
5292895 | if (!(is_const &= value[i]->const_for_execution())) break; |
| 7043 | } | ||
| 7044 |
2/2✓ Branch 0 taken 1134790 times.
✓ Branch 1 taken 3800341 times.
|
4935131 | if (is_const) |
| 7045 | 1134790 | stat[0].const_keys.merge(possible_keys); | |
| 7046 |
2/2✓ Branch 0 taken 1789 times.
✓ Branch 1 taken 3798552 times.
|
3800341 | else if (!eq_func) { |
| 7047 | /* | ||
| 7048 | Save info to be able check whether this predicate can be | ||
| 7049 | considered as sargable for range analysis after reading const tables. | ||
| 7050 | We do not save info about equalities as update_const_equal_items | ||
| 7051 | will take care of updating info on keys from sargable equalities. | ||
| 7052 | */ | ||
| 7053 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1789 times.
|
1789 | assert(sargables); |
| 7054 | 1789 | (*sargables)--; | |
| 7055 | /* | ||
| 7056 | The sargables and key_fields arrays share the same memory | ||
| 7057 | buffer, and grow from opposite directions, so make sure they | ||
| 7058 | don't cross. | ||
| 7059 | */ | ||
| 7060 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1789 times.
|
1789 | assert(*sargables > reinterpret_cast<SARGABLE_PARAM *>(*key_fields)); |
| 7061 | 1789 | (*sargables)->field = field; | |
| 7062 | 1789 | (*sargables)->arg_value = value; | |
| 7063 | 1789 | (*sargables)->num_values = num_values; | |
| 7064 | } | ||
| 7065 | /* | ||
| 7066 | We can't always use indexes when comparing a string index to a | ||
| 7067 | number. cmp_type() is checked to allow compare of dates to numbers. | ||
| 7068 | eq_func is NEVER true when num_values > 1 | ||
| 7069 | */ | ||
| 7070 |
2/2✓ Branch 0 taken 458267 times.
✓ Branch 1 taken 4476848 times.
|
4937157 | if (!eq_func) return false; |
| 7071 | |||
| 7072 | /* | ||
| 7073 | Check if the field and value are comparable in the index. | ||
| 7074 | */ | ||
| 7075 |
2/4✓ Branch 0 taken 4476837 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4476837 times.
✗ Branch 3 not taken.
|
4476848 | if (!comparable_in_index(cond, field, Field::itRAW, cond->functype(), |
| 7076 |
4/4✓ Branch 0 taken 4475014 times.
✓ Branch 1 taken 1823 times.
✓ Branch 2 taken 2042 times.
✓ Branch 3 taken 4474773 times.
|
8951829 | *value) || |
| 7077 |
3/4✓ Branch 0 taken 4474980 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 749089 times.
✓ Branch 3 taken 3725891 times.
|
4475014 | (field->cmp_type() == STRING_RESULT && |
| 7078 |
3/4✓ Branch 0 taken 749091 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 748747 times.
✓ Branch 3 taken 344 times.
|
749089 | field->match_collation_to_optimize_range() && |
| 7079 |
4/6✓ Branch 0 taken 748737 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 748757 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 219 times.
✓ Branch 5 taken 748538 times.
|
748747 | field->charset() != cond->compare_collation())) { |
| 7080 |
1/2✓ Branch 0 taken 2042 times.
✗ Branch 1 not taken.
|
2042 | warn_index_not_applicable(stat->join()->thd, field, possible_keys); |
| 7081 | 2042 | return false; | |
| 7082 | } | ||
| 7083 | } | ||
| 7084 | } | ||
| 7085 | /* | ||
| 7086 | For the moment eq_func is always true. This slot is reserved for future | ||
| 7087 | extensions where we want to remembers other things than just eq comparisons | ||
| 7088 | */ | ||
| 7089 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4475139 times.
|
4475139 | assert(eq_func); |
| 7090 | /* | ||
| 7091 | Calculate the "null rejecting" property based on the type of predicate. | ||
| 7092 | Only the <=> operator and the IS NULL and IS NOT NULL clauses may return | ||
| 7093 | true on nullable operands that have the NULL value - assuming that all | ||
| 7094 | other predicates are augmented with IS TRUE or IS FALSE truth clause, | ||
| 7095 | so that all UNKNOWN results are converted to TRUE or FALSE. | ||
| 7096 | |||
| 7097 | The "null rejecting" property can be combined with the left and right | ||
| 7098 | operands to perform certain optimizations. | ||
| 7099 | |||
| 7100 | If the condition has form "left.field = right.keypart" and left.field can | ||
| 7101 | be NULL, there will be no matches if left.field is NULL. | ||
| 7102 | We use null_rejecting in add_not_null_conds() to add | ||
| 7103 | 'left.field IS NOT NULL' to tab->m_condition, if this is not an outer | ||
| 7104 | join. We also use it to shortcut reading rows from table "right" when | ||
| 7105 | left.field is found to be a NULL value (in RefIterator and BKA). | ||
| 7106 | |||
| 7107 | It is also possible to apply optimizations to the indexed table. | ||
| 7108 | If the operation is null rejecting and there is a unique index over | ||
| 7109 | the key field, an eq_ref operation can be performed on the index, since | ||
| 7110 | we have no interest in the NULL values. | ||
| 7111 | |||
| 7112 | Notice however that the null rejecting property may be cancelled out | ||
| 7113 | by the KEY_OPTIMIZE_REF_OR_NULL property: this can be set when having: | ||
| 7114 | |||
| 7115 | left.field = right.keypart OR right.keypart IS NULL. | ||
| 7116 | */ | ||
| 7117 | 4475139 | const bool null_rejecting = cond->functype() != Item_func::EQUAL_FUNC && | |
| 7118 |
4/4✓ Branch 0 taken 4473822 times.
✓ Branch 1 taken 1307 times.
✓ Branch 2 taken 4469320 times.
✓ Branch 3 taken 4515 times.
|
8944487 | cond->functype() != Item_func::ISNULL_FUNC && |
| 7119 |
1/2✓ Branch 0 taken 4469365 times.
✗ Branch 1 not taken.
|
4469320 | cond->functype() != Item_func::ISNOTNULL_FUNC; |
| 7120 | |||
| 7121 | /* Store possible eq field */ | ||
| 7122 | 4475130 | new (*key_fields) Key_field(item_field, *value, and_level, exists_optimize, | |
| 7123 | eq_func, null_rejecting, nullptr, | ||
| 7124 | 4475180 | get_semi_join_select_list_index(item_field)); | |
| 7125 | 4475172 | (*key_fields)++; | |
| 7126 | /* | ||
| 7127 | The sargables and key_fields arrays share the same memory buffer, | ||
| 7128 | and grow from opposite directions, so make sure they don't | ||
| 7129 | cross. But if sargables was NULL, eq_func had to be true and we | ||
| 7130 | don't write any sargables. | ||
| 7131 | */ | ||
| 7132 |
3/4✓ Branch 0 taken 4474704 times.
✓ Branch 1 taken 468 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4474704 times.
|
4475172 | assert(sargables == nullptr || |
| 7133 | *key_fields < reinterpret_cast<Key_field *>(*sargables)); | ||
| 7134 | |||
| 7135 | 4475172 | return false; | |
| 7136 | } | ||
| 7137 | |||
| 7138 | /** | ||
| 7139 | Add possible keys to array of possible keys originated from a simple | ||
| 7140 | predicate. | ||
| 7141 | |||
| 7142 | @param thd session context | ||
| 7143 | @param[in,out] key_fields Pointer to add key, if usable | ||
| 7144 | is incremented if key was stored in the array | ||
| 7145 | @param and_level And level, to be stored in Key_field | ||
| 7146 | @param cond Condition predicate | ||
| 7147 | @param field_item Field used in comparison | ||
| 7148 | @param eq_func True if we used =, <=> or IS NULL | ||
| 7149 | @param val Value used for comparison with field | ||
| 7150 | Is NULL for BETWEEN and IN | ||
| 7151 | @param num_values Number of elements in the array of values | ||
| 7152 | @param usable_tables Tables which can be used for key optimization | ||
| 7153 | @param sargables IN/OUT Array of found sargable candidates | ||
| 7154 | |||
| 7155 | @note | ||
| 7156 | If field items f1 and f2 belong to the same multiple equality and | ||
| 7157 | a key is added for f1, the the same key is added for f2. | ||
| 7158 | |||
| 7159 | @returns false if success, true if error | ||
| 7160 | */ | ||
| 7161 | |||
| 7162 | 850711 | static bool add_key_equal_fields(THD *thd, Key_field **key_fields, | |
| 7163 | uint and_level, Item_func *cond, | ||
| 7164 | Item_field *field_item, bool eq_func, | ||
| 7165 | Item **val, uint num_values, | ||
| 7166 | table_map usable_tables, | ||
| 7167 | SARGABLE_PARAM **sargables) { | ||
| 7168 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 850711 times.
|
850711 | assert(cond->is_bool_func()); |
| 7169 | |||
| 7170 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 850711 times.
|
850711 | if (add_key_field(thd, key_fields, and_level, cond, field_item, eq_func, val, |
| 7171 | num_values, usable_tables, sargables)) | ||
| 7172 | ✗ | return true; | |
| 7173 | 850711 | Item_equal *item_equal = field_item->item_equal; | |
| 7174 |
2/2✓ Branch 0 taken 845283 times.
✓ Branch 1 taken 5428 times.
|
850711 | if (item_equal == nullptr) return false; |
| 7175 | /* | ||
| 7176 | Add to the set of possible key values every substitution of | ||
| 7177 | the field for an equal field included into item_equal | ||
| 7178 | */ | ||
| 7179 |
5/8✓ Branch 0 taken 5428 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5428 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16450 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 11022 times.
✓ Branch 7 taken 5428 times.
|
16450 | for (Item_field &item : item_equal->get_fields()) { |
| 7180 |
3/4✓ Branch 0 taken 11022 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5594 times.
✓ Branch 3 taken 5428 times.
|
11022 | if (!field_item->field->eq(item.field)) { |
| 7181 |
2/4✓ Branch 0 taken 5594 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5594 times.
|
5594 | if (add_key_field(thd, key_fields, and_level, cond, &item, eq_func, val, |
| 7182 | num_values, usable_tables, sargables)) | ||
| 7183 | ✗ | return true; | |
| 7184 | } | ||
| 7185 | } | ||
| 7186 | 5428 | return false; | |
| 7187 | } | ||
| 7188 | |||
| 7189 | /** | ||
| 7190 | Check if an expression is a non-outer field. | ||
| 7191 | |||
| 7192 | Checks if an expression is a field and belongs to the current select. | ||
| 7193 | |||
| 7194 | @param field Item expression to check | ||
| 7195 | |||
| 7196 | @return boolean | ||
| 7197 | @retval true the expression is a local field | ||
| 7198 | @retval false it's something else | ||
| 7199 | */ | ||
| 7200 | |||
| 7201 | 2231340 | static bool is_local_field(Item *field) { | |
| 7202 | 2231340 | return field->real_item()->type() == Item::FIELD_ITEM && | |
| 7203 |
2/2✓ Branch 0 taken 850649 times.
✓ Branch 1 taken 5208 times.
|
855857 | !field->is_outer_reference() && |
| 7204 |
4/4✓ Branch 0 taken 855857 times.
✓ Branch 1 taken 1375544 times.
✓ Branch 2 taken 850620 times.
✓ Branch 3 taken 29 times.
|
3937867 | !down_cast<Item_ident *>(field)->depended_from && |
| 7205 |
1/2✓ Branch 0 taken 850620 times.
✗ Branch 1 not taken.
|
3082010 | !down_cast<Item_ident *>(field->real_item())->depended_from; |
| 7206 | } | ||
| 7207 | |||
| 7208 | /** | ||
| 7209 | Check if a row constructor expression is over columns in the same query block. | ||
| 7210 | |||
| 7211 | @param item_row Row expression to check. | ||
| 7212 | |||
| 7213 | @return boolean | ||
| 7214 | @retval true The expression is a local column reference. | ||
| 7215 | @retval false It's something else. | ||
| 7216 | */ | ||
| 7217 | 177 | static bool is_row_of_local_columns(Item_row *item_row) { | |
| 7218 |
2/2✓ Branch 0 taken 371 times.
✓ Branch 1 taken 157 times.
|
528 | for (uint i = 0; i < item_row->cols(); ++i) |
| 7219 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 351 times.
|
371 | if (!is_local_field(item_row->element_index(i))) return false; |
| 7220 | 157 | return true; | |
| 7221 | } | ||
| 7222 | |||
| 7223 | /** | ||
| 7224 | The guts of the ref optimizer. This function, along with the other | ||
| 7225 | add_key_* functions, make up a recursive procedure that analyzes a | ||
| 7226 | condition expression (a tree of AND and OR predicates) and does | ||
| 7227 | many things. | ||
| 7228 | |||
| 7229 | @param thd session context | ||
| 7230 | @param join The query block involving the condition. | ||
| 7231 | @param [in,out] key_fields Start of memory buffer, see below. | ||
| 7232 | @param [in,out] and_level Current 'and level', see below. | ||
| 7233 | @param cond The conditional expression to analyze. | ||
| 7234 | @param usable_tables Tables not in this bitmap will not be examined. | ||
| 7235 | @param [in,out] sargables End of memory buffer, see below. | ||
| 7236 | |||
| 7237 | @returns false if success, true if error | ||
| 7238 | |||
| 7239 | This documentation is the result of reverse engineering and may | ||
| 7240 | therefore not capture the full gist of the procedure, but it is | ||
| 7241 | known to do the following: | ||
| 7242 | |||
| 7243 | - Populate a raw memory buffer from two directions at the same time. An | ||
| 7244 | 'array' of Key_field objects fill the buffer from low to high addresses | ||
| 7245 | whilst an 'array' of SARGABLE_PARAM's fills the buffer from high to low | ||
| 7246 | addresses. At the first call to this function, it is assumed that | ||
| 7247 | key_fields points to the beginning of the buffer and sargables point to the | ||
| 7248 | end (except for a poor-mans 'null element' at the very end). | ||
| 7249 | |||
| 7250 | - Update a number of properties in the JOIN_TAB's that can be used | ||
| 7251 | to find search keys (sargables). | ||
| 7252 | |||
| 7253 | - JOIN_TAB::keys | ||
| 7254 | - JOIN_TAB::key_dependent | ||
| 7255 | - JOIN_TAB::const_keys (dictates if the range optimizer will be run | ||
| 7256 | later.) | ||
| 7257 | |||
| 7258 | The Key_field objects are marked with something called an 'and_level', which | ||
| 7259 | does @b not correspond to their nesting depth within the expression tree. It | ||
| 7260 | is rather a tag to group conjunctions together. For instance, in the | ||
| 7261 | conditional expression | ||
| 7262 | |||
| 7263 | @code | ||
| 7264 | a = 0 AND b = 0 | ||
| 7265 | @endcode | ||
| 7266 | |||
| 7267 | two Key_field's are produced, both having an and_level of 0. | ||
| 7268 | |||
| 7269 | In an expression such as | ||
| 7270 | |||
| 7271 | @code | ||
| 7272 | a = 0 AND b = 0 OR a = 1 | ||
| 7273 | @endcode | ||
| 7274 | |||
| 7275 | three Key_field's are produced, the first two corresponding to 'a = 0' and | ||
| 7276 | 'b = 0', respectively, both with and_level 0. The third one corresponds to | ||
| 7277 | 'a = 1' and has an and_level of 1. | ||
| 7278 | |||
| 7279 | A separate function, merge_key_fields() performs ref access validation on | ||
| 7280 | the Key_field array on the recursice ascent. If some Key_field's cannot be | ||
| 7281 | used for ref access, the key_fields pointer is rolled back. All other | ||
| 7282 | modifications to the query plan remain. | ||
| 7283 | */ | ||
| 7284 | 5548730 | bool add_key_fields(THD *thd, JOIN *join, Key_field **key_fields, | |
| 7285 | uint *and_level, Item *cond, table_map usable_tables, | ||
| 7286 | SARGABLE_PARAM **sargables) { | ||
| 7287 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5548829 times.
|
5548730 | assert(cond->is_bool_func()); |
| 7288 | |||
| 7289 |
2/2✓ Branch 0 taken 860561 times.
✓ Branch 1 taken 4688258 times.
|
5548829 | if (cond->type() == Item_func::COND_ITEM) { |
| 7290 |
1/2✓ Branch 0 taken 860588 times.
✗ Branch 1 not taken.
|
860561 | List_iterator_fast<Item> li(*((Item_cond *)cond)->argument_list()); |
| 7291 | 860588 | Key_field *org_key_fields = *key_fields; | |
| 7292 | |||
| 7293 |
3/4✓ Branch 0 taken 860569 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 835030 times.
✓ Branch 3 taken 25539 times.
|
860588 | if (down_cast<Item_cond *>(cond)->functype() == Item_func::COND_AND_FUNC) { |
| 7294 | Item *item; | ||
| 7295 |
2/2✓ Branch 0 taken 3712983 times.
✓ Branch 1 taken 835046 times.
|
4547996 | while ((item = li++)) { |
| 7296 |
2/4✓ Branch 0 taken 3712966 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3712966 times.
|
3712983 | if (add_key_fields(thd, join, key_fields, and_level, item, |
| 7297 | usable_tables, sargables)) | ||
| 7298 | ✗ | return true; | |
| 7299 | } | ||
| 7300 |
2/2✓ Branch 0 taken 3537916 times.
✓ Branch 1 taken 835046 times.
|
4372962 | for (; org_key_fields != *key_fields; org_key_fields++) |
| 7301 | 3537916 | org_key_fields->level = *and_level; | |
| 7302 | } else { | ||
| 7303 | 25539 | (*and_level)++; | |
| 7304 |
2/4✓ Branch 0 taken 25539 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 25539 times.
|
25539 | if (add_key_fields(thd, join, key_fields, and_level, li++, usable_tables, |
| 7305 | sargables)) | ||
| 7306 | ✗ | return true; | |
| 7307 | Item *item; | ||
| 7308 |
2/2✓ Branch 0 taken 41489 times.
✓ Branch 1 taken 25544 times.
|
67033 | while ((item = li++)) { |
| 7309 | 41489 | Key_field *start_key_fields = *key_fields; | |
| 7310 | 41489 | (*and_level)++; | |
| 7311 |
2/4✓ Branch 0 taken 41494 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 41494 times.
|
41489 | if (add_key_fields(thd, join, key_fields, and_level, item, |
| 7312 | usable_tables, sargables)) | ||
| 7313 | ✗ | return true; | |
| 7314 | 41494 | *key_fields = merge_key_fields(org_key_fields, start_key_fields, | |
| 7315 |
1/2✓ Branch 0 taken 41494 times.
✗ Branch 1 not taken.
|
41494 | *key_fields, ++(*and_level)); |
| 7316 | } | ||
| 7317 | } | ||
| 7318 | 860590 | return false; | |
| 7319 | } | ||
| 7320 | |||
| 7321 | /* | ||
| 7322 | Subquery optimization: Conditions that are pushed down into subqueries | ||
| 7323 | are wrapped into Item_func_trig_cond. We process the wrapped condition | ||
| 7324 | but need to set cond_guard for Key_use elements generated from it. | ||
| 7325 | */ | ||
| 7326 |
4/4✓ Branch 0 taken 4687706 times.
✓ Branch 1 taken 520 times.
✓ Branch 2 taken 3601 times.
✓ Branch 3 taken 4684662 times.
|
9376001 | if (cond->type() == Item::FUNC_ITEM && |
| 7327 |
2/2✓ Branch 0 taken 3601 times.
✓ Branch 1 taken 4684142 times.
|
4687706 | down_cast<Item_func *>(cond)->functype() == Item_func::TRIG_COND_FUNC) { |
| 7328 | 3601 | Item *const cond_arg = down_cast<Item_func *>(cond)->arguments()[0]; | |
| 7329 |
1/2✓ Branch 0 taken 3601 times.
✗ Branch 1 not taken.
|
7202 | if (join->group_list.empty() && join->order.empty() && |
| 7330 |
1/2✓ Branch 0 taken 3601 times.
✗ Branch 1 not taken.
|
3601 | join->query_expression()->item && |
| 7331 |
5/6✓ Branch 0 taken 3601 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3261 times.
✓ Branch 3 taken 340 times.
✓ Branch 4 taken 3206 times.
✓ Branch 5 taken 395 times.
|
10463 | join->query_expression()->item->substype() == Item_subselect::IN_SUBS && |
| 7332 |
2/2✓ Branch 0 taken 3206 times.
✓ Branch 1 taken 55 times.
|
3261 | !join->query_expression()->is_union()) { |
| 7333 | 3206 | Key_field *save = *key_fields; | |
| 7334 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3206 times.
|
3206 | if (add_key_fields(thd, join, key_fields, and_level, cond_arg, |
| 7335 | usable_tables, sargables)) | ||
| 7336 | ✗ | return true; | |
| 7337 | // Indicate that this ref access candidate is for subquery lookup: | ||
| 7338 |
2/2✓ Branch 0 taken 918 times.
✓ Branch 1 taken 3206 times.
|
4124 | for (; save != *key_fields; save++) |
| 7339 | 918 | save->cond_guard = ((Item_func_trig_cond *)cond)->get_trig_var(); | |
| 7340 | } | ||
| 7341 | 3601 | return false; | |
| 7342 | } | ||
| 7343 | |||
| 7344 | /* If item is of type 'field op field/constant' add it to key_fields */ | ||
| 7345 |
2/2✓ Branch 0 taken 524 times.
✓ Branch 1 taken 4684124 times.
|
4684662 | if (cond->type() != Item::FUNC_ITEM) return false; |
| 7346 | 4684124 | Item_func *const cond_func = down_cast<Item_func *>(cond); | |
| 7347 | 4684194 | auto optimize = cond_func->select_optimize(thd); | |
| 7348 | // Catch errors that might be thrown during select_optimize() | ||
| 7349 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4684092 times.
|
4684181 | if (thd->is_error()) return true; |
| 7350 |
6/6✓ Branch 0 taken 251706 times.
✓ Branch 1 taken 1059572 times.
✓ Branch 2 taken 456913 times.
✓ Branch 3 taken 26622 times.
✓ Branch 4 taken 2889248 times.
✓ Branch 5 taken 31 times.
|
4684092 | switch (optimize) { |
| 7351 | 251706 | case Item_func::OPTIMIZE_NONE: | |
| 7352 | 4684038 | break; | |
| 7353 | 1059572 | case Item_func::OPTIMIZE_KEY: { | |
| 7354 | Item **values; | ||
| 7355 | /* | ||
| 7356 | Build list of possible keys for 'a BETWEEN low AND high'. | ||
| 7357 | It is handled similar to the equivalent condition | ||
| 7358 | 'a >= low AND a <= high': | ||
| 7359 | */ | ||
| 7360 |
3/4✓ Branch 0 taken 1059587 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21873 times.
✓ Branch 3 taken 1037714 times.
|
1059572 | if (cond_func->functype() == Item_func::BETWEEN) { |
| 7361 | Item_field *field_item; | ||
| 7362 | 21873 | bool equal_func = false; | |
| 7363 | 21873 | uint num_values = 2; | |
| 7364 |
1/2✓ Branch 0 taken 21873 times.
✗ Branch 1 not taken.
|
21873 | values = cond_func->arguments(); |
| 7365 | |||
| 7366 | bool binary_cmp = | ||
| 7367 |
2/4✓ Branch 0 taken 21873 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21873 times.
✗ Branch 3 not taken.
|
21873 | (values[0]->real_item()->type() == Item::FIELD_ITEM) |
| 7368 |
6/8✓ Branch 0 taken 20626 times.
✓ Branch 1 taken 1247 times.
✓ Branch 2 taken 20626 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 20626 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 20440 times.
✓ Branch 7 taken 186 times.
|
21873 | ? ((Item_field *)values[0]->real_item())->field->binary() |
| 7369 | 21873 | : true; | |
| 7370 | |||
| 7371 | /* | ||
| 7372 | Additional optimization: If 'low = high': | ||
| 7373 | Handle as if the condition was "t.key = low". | ||
| 7374 | */ | ||
| 7375 |
4/4✓ Branch 0 taken 21690 times.
✓ Branch 1 taken 183 times.
✓ Branch 2 taken 61 times.
✓ Branch 3 taken 21812 times.
|
43563 | if (!((Item_func_between *)cond_func)->negated && |
| 7376 |
3/4✓ Branch 0 taken 21690 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
✓ Branch 3 taken 21629 times.
|
21690 | values[1]->eq(values[2], binary_cmp)) { |
| 7377 | 61 | equal_func = true; | |
| 7378 | 61 | num_values = 1; | |
| 7379 | } | ||
| 7380 | |||
| 7381 | /* | ||
| 7382 | Append keys for 'field <cmp> value[]' if the | ||
| 7383 | condition is of the form:: | ||
| 7384 | '<field> BETWEEN value[1] AND value[2]' | ||
| 7385 | */ | ||
| 7386 |
3/4✓ Branch 0 taken 21873 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20626 times.
✓ Branch 3 taken 1247 times.
|
21873 | if (is_local_field(values[0])) { |
| 7387 |
1/2✓ Branch 0 taken 20626 times.
✗ Branch 1 not taken.
|
20626 | field_item = (Item_field *)(values[0]->real_item()); |
| 7388 |
2/4✓ Branch 0 taken 20626 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20626 times.
|
20626 | if (add_key_equal_fields(thd, key_fields, *and_level, cond_func, |
| 7389 | field_item, equal_func, &values[1], | ||
| 7390 | num_values, usable_tables, sargables)) | ||
| 7391 | ✗ | return true; | |
| 7392 | } | ||
| 7393 | /* | ||
| 7394 | Append keys for 'value[0] <cmp> field' if the | ||
| 7395 | condition is of the form: | ||
| 7396 | 'value[0] BETWEEN field1 AND field2' | ||
| 7397 | */ | ||
| 7398 |
2/2✓ Branch 0 taken 43685 times.
✓ Branch 1 taken 21873 times.
|
65558 | for (uint i = 1; i <= num_values; i++) { |
| 7399 |
3/4✓ Branch 0 taken 43685 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 387 times.
✓ Branch 3 taken 43298 times.
|
43685 | if (is_local_field(values[i])) { |
| 7400 |
1/2✓ Branch 0 taken 387 times.
✗ Branch 1 not taken.
|
387 | field_item = (Item_field *)(values[i]->real_item()); |
| 7401 |
2/4✓ Branch 0 taken 387 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 387 times.
|
387 | if (add_key_equal_fields(thd, key_fields, *and_level, cond_func, |
| 7402 | field_item, equal_func, values, 1, | ||
| 7403 | usable_tables, sargables)) | ||
| 7404 | ✗ | return true; | |
| 7405 | } | ||
| 7406 | } | ||
| 7407 | } // if ( ... Item_func::BETWEEN) | ||
| 7408 |
5/6✓ Branch 0 taken 1037691 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 464 times.
✓ Branch 3 taken 1037227 times.
✓ Branch 4 taken 441 times.
✓ Branch 5 taken 1037250 times.
|
1038178 | else if (cond_func->functype() == Item_func::MEMBER_OF_FUNC && |
| 7409 |
4/6✓ Branch 0 taken 464 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 464 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 441 times.
✓ Branch 5 taken 23 times.
|
464 | is_local_field(cond_func->key_item())) { |
| 7410 | // The predicate is <val> IN (<typed array>) | ||
| 7411 |
1/2✓ Branch 0 taken 441 times.
✗ Branch 1 not taken.
|
441 | add_key_equal_fields(thd, key_fields, *and_level, cond_func, |
| 7412 |
3/6✓ Branch 0 taken 441 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 441 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 436 times.
✗ Branch 5 not taken.
|
441 | (Item_field *)(cond_func->key_item()->real_item()), |
| 7413 | true, cond_func->arguments(), 1, usable_tables, | ||
| 7414 | sargables); | ||
| 7415 |
5/6✓ Branch 0 taken 1037241 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1037112 times.
✓ Branch 3 taken 129 times.
✓ Branch 4 taken 256 times.
✓ Branch 5 taken 1037017 times.
|
2074394 | } else if (cond_func->functype() == Item_func::JSON_CONTAINS || |
| 7416 |
3/4✓ Branch 0 taken 1037144 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
✓ Branch 3 taken 1037027 times.
|
1037112 | cond_func->functype() == Item_func::JSON_OVERLAPS) { |
| 7417 | /* | ||
| 7418 | Applicability analysis was done during substitute_gc(). | ||
| 7419 | Check here that a typed array field is used and there's a key over | ||
| 7420 | it. | ||
| 7421 | 1) func has a key item | ||
| 7422 | 2) key item is a local field | ||
| 7423 | 3) key item is a typed array field | ||
| 7424 | If so, mark appropriate index as available for range optimizer | ||
| 7425 | */ | ||
| 7426 |
1/2✓ Branch 0 taken 256 times.
✗ Branch 1 not taken.
|
256 | if (!cond_func->key_item() || // 1 |
| 7427 |
8/10✓ Branch 0 taken 245 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 245 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 245 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 213 times.
✓ Branch 7 taken 32 times.
✓ Branch 8 taken 44 times.
✓ Branch 9 taken 212 times.
|
469 | !is_local_field(cond_func->key_item()) || // 2 |
| 7428 |
4/6✓ Branch 0 taken 213 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 213 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 212 times.
|
213 | !cond_func->key_item()->returns_array()) // 3 |
| 7429 | 44 | break; | |
| 7430 | const Field *field = | ||
| 7431 |
1/2✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
|
212 | (down_cast<const Item_field *>(cond_func->key_item()))->field; |
| 7432 | 212 | JOIN_TAB *tab = field->table->reginfo.join_tab; | |
| 7433 | 212 | Key_map possible_keys = field->key_start; | |
| 7434 | |||
| 7435 | 212 | possible_keys.intersect(field->table->keys_in_use_for_query); | |
| 7436 | 212 | tab->keys().merge(possible_keys); // Add possible keys | |
| 7437 | 212 | tab->const_keys.merge(possible_keys); // Add possible keys | |
| 7438 | } // if (... Item_func::CONTAINS) | ||
| 7439 | // The predicate is IN or <> | ||
| 7440 |
6/8✓ Branch 0 taken 1036985 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1037039 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 332138 times.
✓ Branch 5 taken 704901 times.
✓ Branch 6 taken 332000 times.
✓ Branch 7 taken 705039 times.
|
1369155 | else if (is_local_field(cond_func->key_item()) && |
| 7441 |
3/4✓ Branch 0 taken 332138 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 332000 times.
✓ Branch 3 taken 138 times.
|
332138 | !cond_func->is_outer_reference()) { |
| 7442 |
1/2✓ Branch 0 taken 332000 times.
✗ Branch 1 not taken.
|
332000 | values = cond_func->arguments() + 1; |
| 7443 |
5/6✓ Branch 0 taken 332000 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187274 times.
✓ Branch 3 taken 144726 times.
✓ Branch 4 taken 2055 times.
✓ Branch 5 taken 329945 times.
|
519274 | if (cond_func->functype() == Item_func::NE_FUNC && |
| 7444 |
4/6✓ Branch 0 taken 187274 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187274 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2055 times.
✓ Branch 5 taken 185219 times.
|
187274 | is_local_field(cond_func->arguments()[1])) |
| 7445 | 2055 | values--; | |
| 7446 |
5/8✓ Branch 0 taken 332000 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 144726 times.
✓ Branch 3 taken 187274 times.
✓ Branch 4 taken 144726 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 144726 times.
|
332000 | assert(cond_func->functype() != Item_func::IN_FUNC || |
| 7447 | cond_func->argument_count() != 2); | ||
| 7448 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 332000 times.
|
332000 | if (add_key_equal_fields( |
| 7449 | thd, key_fields, *and_level, cond_func, | ||
| 7450 |
2/4✓ Branch 0 taken 332000 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 332000 times.
✗ Branch 3 not taken.
|
332000 | (Item_field *)(cond_func->key_item()->real_item()), false, |
| 7451 |
2/4✓ Branch 0 taken 332000 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 332000 times.
✗ Branch 3 not taken.
|
332000 | values, cond_func->argument_count() - 1, usable_tables, |
| 7452 | sargables)) | ||
| 7453 | ✗ | return true; | |
| 7454 |
5/6✓ Branch 0 taken 704981 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3289 times.
✓ Branch 3 taken 701692 times.
✓ Branch 4 taken 177 times.
✓ Branch 5 taken 704804 times.
|
708328 | } else if (cond_func->functype() == Item_func::IN_FUNC && |
| 7455 |
4/6✓ Branch 0 taken 3289 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3289 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 177 times.
✓ Branch 5 taken 3112 times.
|
3289 | cond_func->key_item()->type() == Item::ROW_ITEM) { |
| 7456 | /* | ||
| 7457 | The condition is (column1, column2, ... ) IN ((const1_1, const1_2), | ||
| 7458 | ...) and there is an index on (column1, column2, ...) | ||
| 7459 | |||
| 7460 | The code below makes sure that the row constructor on the lhs indeed | ||
| 7461 | contains only column references before calling add_key_field on them. | ||
| 7462 | |||
| 7463 | We can't do a ref access on IN, yet here we are. Why? We need | ||
| 7464 | to run add_key_field() only because it verifies that there are | ||
| 7465 | only constant expressions in the rows on the IN's rhs, see | ||
| 7466 | comment above the call to add_key_field() below. | ||
| 7467 | |||
| 7468 | Actually, We could in theory do a ref access if the IN rhs | ||
| 7469 | contained just a single row, but there is a hack in the parser | ||
| 7470 | causing such IN predicates be parsed as row equalities. | ||
| 7471 | */ | ||
| 7472 |
1/2✓ Branch 0 taken 177 times.
✗ Branch 1 not taken.
|
177 | Item_row *lhs_row = static_cast<Item_row *>(cond_func->key_item()); |
| 7473 |
3/4✓ Branch 0 taken 177 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 157 times.
✓ Branch 3 taken 20 times.
|
177 | if (is_row_of_local_columns(lhs_row)) { |
| 7474 |
3/4✓ Branch 0 taken 503 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 346 times.
✓ Branch 3 taken 157 times.
|
503 | for (uint i = 0; i < lhs_row->cols(); ++i) { |
| 7475 |
2/4✓ Branch 0 taken 346 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 346 times.
✗ Branch 3 not taken.
|
346 | Item *const lhs_item = lhs_row->element_index(i)->real_item(); |
| 7476 |
2/4✓ Branch 0 taken 346 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 346 times.
|
346 | assert(lhs_item->type() == Item::FIELD_ITEM); |
| 7477 | 346 | Item_field *const lhs_column = static_cast<Item_field *>(lhs_item); | |
| 7478 | // j goes from 1 since arguments()[0] is the lhs of IN. | ||
| 7479 |
3/4✓ Branch 0 taken 1082 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 736 times.
✓ Branch 3 taken 346 times.
|
1082 | for (uint j = 1; j < cond_func->argument_count(); ++j) { |
| 7480 | // Here we pick out the i:th column in the j:th row. | ||
| 7481 |
1/2✓ Branch 0 taken 736 times.
✗ Branch 1 not taken.
|
736 | Item *rhs_item = cond_func->arguments()[j]; |
| 7482 |
2/4✓ Branch 0 taken 736 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 736 times.
|
736 | assert(rhs_item->type() == Item::ROW_ITEM); |
| 7483 | 736 | Item_row *rhs_row = static_cast<Item_row *>(rhs_item); | |
| 7484 |
3/6✓ Branch 0 taken 736 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 736 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 736 times.
|
736 | assert(rhs_row->cols() == lhs_row->cols()); |
| 7485 |
1/2✓ Branch 0 taken 736 times.
✗ Branch 1 not taken.
|
736 | Item **rhs_expr_ptr = rhs_row->addr(i); |
| 7486 | /* | ||
| 7487 | add_key_field() will write a Key_field on each call | ||
| 7488 | here, but we don't care, it will never be used. We only | ||
| 7489 | call it for the side effect: update JOIN_TAB::const_keys | ||
| 7490 | so the range optimizer can be invoked. We pass a | ||
| 7491 | scrap buffer and pointer here. | ||
| 7492 | */ | ||
| 7493 | 736 | Key_field scrap_key_field = **key_fields; | |
| 7494 | 736 | Key_field *scrap_key_field_ptr = &scrap_key_field; | |
| 7495 |
2/4✓ Branch 0 taken 736 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 736 times.
|
736 | if (add_key_field(thd, &scrap_key_field_ptr, *and_level, |
| 7496 | cond_func, lhs_column, | ||
| 7497 | true, // eq_func | ||
| 7498 | rhs_expr_ptr, | ||
| 7499 | 1, // Number of expressions: one | ||
| 7500 | usable_tables, | ||
| 7501 | nullptr)) // sargables | ||
| 7502 | ✗ | return true; | |
| 7503 | // The pointer is not supposed to increase by more than one. | ||
| 7504 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 736 times.
|
736 | assert(scrap_key_field_ptr <= &scrap_key_field + 1); |
| 7505 | } | ||
| 7506 | } | ||
| 7507 | } | ||
| 7508 | } | ||
| 7509 | 1059502 | break; | |
| 7510 | } | ||
| 7511 | 456913 | case Item_func::OPTIMIZE_OP: { | |
| 7512 |
3/4✓ Branch 0 taken 456913 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 238587 times.
✓ Branch 3 taken 218326 times.
|
695500 | bool equal_func = (cond_func->functype() == Item_func::EQ_FUNC || |
| 7513 |
3/4✓ Branch 0 taken 238587 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2239 times.
✓ Branch 3 taken 236348 times.
|
238587 | cond_func->functype() == Item_func::EQUAL_FUNC); |
| 7514 | |||
| 7515 |
4/6✓ Branch 0 taken 456913 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 456913 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 426195 times.
✓ Branch 5 taken 30718 times.
|
456913 | if (is_local_field(cond_func->arguments()[0])) { |
| 7516 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 426195 times.
|
426195 | if (add_key_equal_fields( |
| 7517 | thd, key_fields, *and_level, cond_func, | ||
| 7518 |
2/4✓ Branch 0 taken 426195 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 426195 times.
✗ Branch 3 not taken.
|
426195 | (Item_field *)(cond_func->arguments()[0])->real_item(), |
| 7519 |
2/4✓ Branch 0 taken 426195 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 426195 times.
✗ Branch 3 not taken.
|
426195 | equal_func, cond_func->arguments() + 1, 1, usable_tables, |
| 7520 | sargables)) | ||
| 7521 | ✗ | return true; | |
| 7522 | } else { | ||
| 7523 |
2/4✓ Branch 0 taken 30718 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30718 times.
✗ Branch 3 not taken.
|
30718 | Item *real_item = cond_func->arguments()[0]->real_item(); |
| 7524 |
3/4✓ Branch 0 taken 30718 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17656 times.
✓ Branch 3 taken 13062 times.
|
30718 | if (real_item->type() == Item::FUNC_ITEM) { |
| 7525 | 17656 | Item_func *func_item = down_cast<Item_func *>(real_item); | |
| 7526 |
3/4✓ Branch 0 taken 17656 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2860 times.
✓ Branch 3 taken 14796 times.
|
17656 | if (func_item->functype() == Item_func::COLLATE_FUNC) { |
| 7527 |
1/2✓ Branch 0 taken 2860 times.
✗ Branch 1 not taken.
|
2860 | Item *key_item = func_item->key_item(); |
| 7528 |
3/4✓ Branch 0 taken 2860 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2827 times.
✓ Branch 3 taken 33 times.
|
2860 | if (key_item->type() == Item::FIELD_ITEM) { |
| 7529 |
2/4✓ Branch 0 taken 2827 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2827 times.
|
2827 | if (add_key_equal_fields(thd, key_fields, *and_level, cond_func, |
| 7530 | down_cast<Item_field *>(key_item), | ||
| 7531 |
1/2✓ Branch 0 taken 2827 times.
✗ Branch 1 not taken.
|
2827 | equal_func, cond_func->arguments() + 1, |
| 7532 | 1, usable_tables, sargables)) | ||
| 7533 | ✗ | return true; | |
| 7534 | } | ||
| 7535 | } | ||
| 7536 | } | ||
| 7537 | } | ||
| 7538 |
6/8✓ Branch 0 taken 456913 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 456913 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 42838 times.
✓ Branch 5 taken 414075 times.
✓ Branch 6 taken 42838 times.
✓ Branch 7 taken 414075 times.
|
499751 | if (is_local_field(cond_func->arguments()[1]) && |
| 7539 |
2/4✓ Branch 0 taken 42838 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42838 times.
✗ Branch 3 not taken.
|
42838 | cond_func->functype() != Item_func::LIKE_FUNC) { |
| 7540 |
2/4✓ Branch 0 taken 42838 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 42838 times.
|
85676 | if (add_key_equal_fields( |
| 7541 | thd, key_fields, *and_level, cond_func, | ||
| 7542 |
3/6✓ Branch 0 taken 42838 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42838 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 42838 times.
✗ Branch 5 not taken.
|
42838 | (Item_field *)(cond_func->arguments()[1])->real_item(), |
| 7543 | equal_func, cond_func->arguments(), 1, usable_tables, | ||
| 7544 | sargables)) | ||
| 7545 | ✗ | return true; | |
| 7546 | } else { | ||
| 7547 |
2/4✓ Branch 0 taken 414075 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 414075 times.
✗ Branch 3 not taken.
|
414075 | Item *real_item = cond_func->arguments()[1]->real_item(); |
| 7548 |
3/4✓ Branch 0 taken 414075 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22180 times.
✓ Branch 3 taken 391895 times.
|
414075 | if (real_item->type() == Item::FUNC_ITEM) { |
| 7549 | 22180 | Item_func *func_item = down_cast<Item_func *>(real_item); | |
| 7550 |
3/4✓ Branch 0 taken 22180 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 71 times.
✓ Branch 3 taken 22109 times.
|
22180 | if (func_item->functype() == Item_func::COLLATE_FUNC) { |
| 7551 |
1/2✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
|
71 | Item *key_item = func_item->key_item(); |
| 7552 |
3/4✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 50 times.
|
71 | if (key_item->type() == Item::FIELD_ITEM) { |
| 7553 |
3/6✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 21 times.
|
21 | if (add_key_equal_fields(thd, key_fields, *and_level, cond_func, |
| 7554 | down_cast<Item_field *>(key_item), | ||
| 7555 | equal_func, cond_func->arguments(), 1, | ||
| 7556 | usable_tables, sargables)) | ||
| 7557 | ✗ | return true; | |
| 7558 | } | ||
| 7559 | } | ||
| 7560 | } | ||
| 7561 | } | ||
| 7562 | |||
| 7563 | 456913 | break; | |
| 7564 | } | ||
| 7565 | 26622 | case Item_func::OPTIMIZE_NULL: | |
| 7566 | /* column_name IS [NOT] NULL */ | ||
| 7567 |
6/8✓ Branch 0 taken 26622 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26622 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 25376 times.
✓ Branch 5 taken 1246 times.
✓ Branch 6 taken 25376 times.
✓ Branch 7 taken 1246 times.
|
51998 | if (is_local_field(cond_func->arguments()[0]) && |
| 7568 |
2/4✓ Branch 0 taken 25376 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25376 times.
✗ Branch 3 not taken.
|
25376 | !cond_func->is_outer_reference()) { |
| 7569 |
2/4✓ Branch 0 taken 25376 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25376 times.
✗ Branch 3 not taken.
|
25376 | Item *tmp = new Item_null; |
| 7570 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25376 times.
|
25376 | if (tmp == nullptr) return true; |
| 7571 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25376 times.
|
25376 | if (add_key_equal_fields( |
| 7572 | thd, key_fields, *and_level, cond_func, | ||
| 7573 |
2/4✓ Branch 0 taken 25376 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25376 times.
✗ Branch 3 not taken.
|
25376 | (Item_field *)(cond_func->arguments()[0])->real_item(), |
| 7574 |
2/4✓ Branch 0 taken 25376 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25376 times.
✗ Branch 3 not taken.
|
25376 | cond_func->functype() == Item_func::ISNULL_FUNC, &tmp, 1, |
| 7575 | usable_tables, sargables)) | ||
| 7576 | ✗ | return true; | |
| 7577 | } | ||
| 7578 | 26622 | break; | |
| 7579 | 2889248 | case Item_func::OPTIMIZE_EQUAL: | |
| 7580 | 2889248 | Item_equal *item_equal = (Item_equal *)cond; | |
| 7581 | 2889248 | Item *const_item = item_equal->get_const(); | |
| 7582 |
2/2✓ Branch 0 taken 926385 times.
✓ Branch 1 taken 1962857 times.
|
2889242 | if (const_item) { |
| 7583 | /* | ||
| 7584 | For each field field1 from item_equal consider the equality | ||
| 7585 | field1=const_item as a condition allowing an index access of the table | ||
| 7586 | with field1 by the keys value of field1. | ||
| 7587 | */ | ||
| 7588 |
5/8✓ Branch 0 taken 926419 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 926449 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2012990 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1086549 times.
✓ Branch 7 taken 926441 times.
|
2012968 | for (Item_field &item : item_equal->get_fields()) { |
| 7589 |
2/4✓ Branch 0 taken 1086583 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1086583 times.
|
1086553 | if (add_key_field(thd, key_fields, *and_level, cond_func, &item, true, |
| 7590 | &const_item, 1, usable_tables, sargables)) | ||
| 7591 | ✗ | return true; | |
| 7592 | } | ||
| 7593 | } else { | ||
| 7594 | /* | ||
| 7595 | Consider all pairs of different fields included into item_equal. | ||
| 7596 | For each of them (field1, field1) consider the equality | ||
| 7597 | field1=field2 as a condition allowing an index access of the table | ||
| 7598 | with field1 by the keys value of field2. | ||
| 7599 | */ | ||
| 7600 |
5/8✓ Branch 0 taken 1962856 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1962850 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5918139 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3955329 times.
✓ Branch 7 taken 1962810 times.
|
5918161 | for (Item_field &outer : item_equal->get_fields()) { |
| 7601 |
5/8✓ Branch 0 taken 3955415 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3955392 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12764239 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8808935 times.
✓ Branch 7 taken 3955304 times.
|
12764270 | for (Item_field &inner : item_equal->get_fields()) { |
| 7602 |
3/4✓ Branch 0 taken 8808865 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4853535 times.
✓ Branch 3 taken 3955330 times.
|
8808929 | if (!outer.field->eq(inner.field)) { |
| 7603 | 4853535 | Item *inner_ptr = &inner; | |
| 7604 |
2/4✓ Branch 0 taken 4853558 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4853558 times.
|
4853535 | if (add_key_field(thd, key_fields, *and_level, cond_func, &outer, |
| 7605 | true, &inner_ptr, 1, usable_tables, sargables)) | ||
| 7606 | ✗ | return true; | |
| 7607 | } | ||
| 7608 | } | ||
| 7609 | } | ||
| 7610 | } | ||
| 7611 | 2889251 | break; | |
| 7612 | } | ||
| 7613 | 4684069 | return false; | |
| 7614 | } | ||
| 7615 | |||
| 7616 | /* | ||
| 7617 | Add all keys with uses 'field' for some keypart | ||
| 7618 | If field->and_level != and_level then only mark key_part as const_part | ||
| 7619 | |||
| 7620 | RETURN | ||
| 7621 | 0 - OK | ||
| 7622 | 1 - Out of memory. | ||
| 7623 | */ | ||
| 7624 | |||
| 7625 | 4467892 | static bool add_key_part(Key_use_array *keyuse_array, Key_field *key_field) { | |
| 7626 |
3/4✓ Branch 0 taken 4467916 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4467617 times.
✓ Branch 3 taken 299 times.
|
4467892 | if (key_field->eq_func && !(key_field->optimize & KEY_OPTIMIZE_EXISTS)) { |
| 7627 | 4467617 | const Field *const field = key_field->item_field->field; | |
| 7628 | 4467617 | TABLE_LIST *const tl = key_field->item_field->table_ref; | |
| 7629 | 4467617 | TABLE *const table = tl->table; | |
| 7630 | |||
| 7631 |
2/2✓ Branch 0 taken 17112641 times.
✓ Branch 1 taken 4467935 times.
|
21580576 | for (uint key = 0; key < table->s->keys; key++) { |
| 7632 |
2/2✓ Branch 0 taken 6777 times.
✓ Branch 1 taken 17105907 times.
|
17112641 | if (!(table->keys_in_use_for_query.is_set(key))) continue; |
| 7633 |
2/2✓ Branch 0 taken 406 times.
✓ Branch 1 taken 17105501 times.
|
17105907 | if (table->key_info[key].flags & (HA_FULLTEXT | HA_SPATIAL)) |
| 7634 | 406 | continue; // ToDo: ft-keys in non-ft queries. SerG | |
| 7635 | |||
| 7636 | 17105501 | uint key_parts = actual_key_parts(&table->key_info[key]); | |
| 7637 |
2/2✓ Branch 0 taken 29191430 times.
✓ Branch 1 taken 17105776 times.
|
46297206 | for (uint part = 0; part < key_parts; part++) { |
| 7638 |
2/2✓ Branch 0 taken 6590941 times.
✓ Branch 1 taken 22600828 times.
|
29191430 | if (field->eq(table->key_info[key].key_part[part].field)) { |
| 7639 | const Key_use keyuse(tl, key_field->val, | ||
| 7640 | 6590941 | key_field->val->used_tables(), key, part, | |
| 7641 | 6590941 | key_field->optimize & KEY_OPTIMIZE_REF_OR_NULL, | |
| 7642 | (key_part_map)1 << part, | ||
| 7643 | ~(ha_rows)0, // will be set in optimize_keyuse | ||
| 7644 | 6590941 | key_field->null_rejecting, key_field->cond_guard, | |
| 7645 |
1/2✓ Branch 0 taken 6590798 times.
✗ Branch 1 not taken.
|
6590941 | key_field->sj_pred_no); |
| 7646 |
2/4✓ Branch 0 taken 6590776 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6590776 times.
|
6590782 | if (keyuse_array->push_back(keyuse)) |
| 7647 | ✗ | return true; /* purecov: inspected */ | |
| 7648 | } | ||
| 7649 | } | ||
| 7650 | } | ||
| 7651 | } | ||
| 7652 | 4468210 | return false; | |
| 7653 | } | ||
| 7654 | |||
| 7655 | /** | ||
| 7656 | Function parses WHERE condition and add key_use for FT index | ||
| 7657 | into key_use array if suitable MATCH function is found. | ||
| 7658 | Condition should be a set of AND expression, OR is not supported. | ||
| 7659 | MATCH function should be a part of simple expression. | ||
| 7660 | Simple expression is MATCH only function or MATCH is a part of | ||
| 7661 | comparison expression ('>=' or '>' operations are supported). | ||
| 7662 | It also sets FT_HINTS values(op_type, op_value). | ||
| 7663 | |||
| 7664 | @param keyuse_array Key_use array | ||
| 7665 | @param cond WHERE condition | ||
| 7666 | @param usable_tables usable tables | ||
| 7667 | @param simple_match_expr true if this is the first call false otherwise. | ||
| 7668 | if MATCH function is found at first call it means | ||
| 7669 | that MATCH is simple expression, otherwise, in case | ||
| 7670 | of AND/OR condition this parameter will be false. | ||
| 7671 | |||
| 7672 | @retval | ||
| 7673 | true if FT key was added to Key_use array | ||
| 7674 | @retval | ||
| 7675 | false if no key was added to Key_use array | ||
| 7676 | |||
| 7677 | */ | ||
| 7678 | |||
| 7679 | 2560 | static bool add_ft_keys(Key_use_array *keyuse_array, Item *cond, | |
| 7680 | table_map usable_tables, bool simple_match_expr) { | ||
| 7681 | 2560 | Item_func_match *cond_func = nullptr; | |
| 7682 | |||
| 7683 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2552 times.
|
2560 | if (!cond) return false; |
| 7684 | |||
| 7685 |
2/4✓ Branch 0 taken 2552 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2552 times.
|
2552 | assert(cond->is_bool_func()); |
| 7686 | |||
| 7687 |
3/4✓ Branch 0 taken 2552 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2405 times.
✓ Branch 3 taken 147 times.
|
2552 | if (cond->type() == Item::FUNC_ITEM) { |
| 7688 | 2405 | Item_func *func = down_cast<Item_func *>(cond); | |
| 7689 |
1/2✓ Branch 0 taken 2405 times.
✗ Branch 1 not taken.
|
2405 | Item_func::Functype functype = func->functype(); |
| 7690 |
2/2✓ Branch 0 taken 2181 times.
✓ Branch 1 taken 224 times.
|
2405 | if (functype == Item_func::MATCH_FUNC) { |
| 7691 |
1/2✓ Branch 0 taken 2181 times.
✗ Branch 1 not taken.
|
2181 | func = down_cast<Item_func *>(func->arguments()[0]); |
| 7692 |
1/2✓ Branch 0 taken 2181 times.
✗ Branch 1 not taken.
|
2181 | functype = func->functype(); |
| 7693 | } | ||
| 7694 | 2405 | enum ft_operation op_type = FT_OP_NO; | |
| 7695 | 2405 | double op_value = 0.0; | |
| 7696 |
2/2✓ Branch 0 taken 2181 times.
✓ Branch 1 taken 224 times.
|
2405 | if (functype == Item_func::FT_FUNC) { |
| 7697 |
1/2✓ Branch 0 taken 2181 times.
✗ Branch 1 not taken.
|
2181 | cond_func = down_cast<Item_func_match *>(func)->get_master(); |
| 7698 | 2181 | cond_func->set_hints_op(op_type, op_value); | |
| 7699 |
2/2✓ Branch 0 taken 127 times.
✓ Branch 1 taken 97 times.
|
224 | } else if (func->arg_count == 2) { |
| 7700 |
1/2✓ Branch 0 taken 127 times.
✗ Branch 1 not taken.
|
127 | Item *arg0 = func->arguments()[0]; |
| 7701 |
1/2✓ Branch 0 taken 127 times.
✗ Branch 1 not taken.
|
127 | Item *arg1 = func->arguments()[1]; |
| 7702 |
10/12✓ Branch 0 taken 127 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 77 times.
✓ Branch 4 taken 50 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 35 times.
✓ Branch 7 taken 15 times.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 31 times.
✓ Branch 10 taken 33 times.
✓ Branch 11 taken 94 times.
|
162 | if (arg1->const_item() && is_function_of_type(arg0, Item_func::FT_FUNC) && |
| 7703 | 4 | ((functype == Item_func::GE_FUNC && | |
| 7704 |
5/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 31 times.
✓ Branch 5 taken 2 times.
|
35 | (op_value = arg1->val_real()) > 0) || |
| 7705 | 31 | (functype == Item_func::GT_FUNC && | |
| 7706 |
2/4✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
|
31 | (op_value = arg1->val_real()) >= 0))) { |
| 7707 |
1/2✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
|
33 | cond_func = down_cast<Item_func_match *>(arg0)->get_master(); |
| 7708 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 31 times.
|
33 | if (functype == Item_func::GE_FUNC) |
| 7709 | 2 | op_type = FT_OP_GE; | |
| 7710 |
1/2✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
|
31 | else if (functype == Item_func::GT_FUNC) |
| 7711 | 31 | op_type = FT_OP_GT; | |
| 7712 | 33 | cond_func->set_hints_op(op_type, op_value); | |
| 7713 |
1/2✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
|
94 | } else if (arg0->const_item() && |
| 7714 |
9/10✓ Branch 0 taken 55 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 45 times.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 8 times.
✓ Branch 9 taken 86 times.
|
104 | is_function_of_type(arg1, Item_func::FT_FUNC) && |
| 7715 | 6 | ((functype == Item_func::LE_FUNC && | |
| 7716 |
5/6✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 2 times.
|
10 | (op_value = arg0->val_real()) > 0) || |
| 7717 | 4 | (functype == Item_func::LT_FUNC && | |
| 7718 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | (op_value = arg0->val_real()) >= 0))) { |
| 7719 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | cond_func = down_cast<Item_func_match *>(arg1)->get_master(); |
| 7720 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | if (functype == Item_func::LE_FUNC) |
| 7721 | 4 | op_type = FT_OP_GE; | |
| 7722 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | else if (functype == Item_func::LT_FUNC) |
| 7723 | 4 | op_type = FT_OP_GT; | |
| 7724 | 8 | cond_func->set_hints_op(op_type, op_value); | |
| 7725 | } | ||
| 7726 | } | ||
| 7727 |
2/4✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 147 times.
✗ Branch 3 not taken.
|
147 | } else if (cond->type() == Item::COND_ITEM) { |
| 7728 |
1/2✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
|
147 | List_iterator_fast<Item> li(*down_cast<Item_cond *>(cond)->argument_list()); |
| 7729 | |||
| 7730 |
3/4✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 142 times.
✓ Branch 3 taken 5 times.
|
147 | if (down_cast<Item_cond *>(cond)->functype() == Item_func::COND_AND_FUNC) { |
| 7731 | Item *item; | ||
| 7732 |
2/2✓ Branch 0 taken 306 times.
✓ Branch 1 taken 142 times.
|
448 | while ((item = li++)) |
| 7733 |
2/4✓ Branch 0 taken 306 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 306 times.
|
306 | if (add_ft_keys(keyuse_array, item, usable_tables, false)) return true; |
| 7734 | } | ||
| 7735 | } | ||
| 7736 | |||
| 7737 |
6/6✓ Branch 0 taken 2222 times.
✓ Branch 1 taken 330 times.
✓ Branch 2 taken 2201 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 356 times.
✓ Branch 5 taken 2196 times.
|
4753 | if (!cond_func || cond_func->key == NO_SUCH_KEY || |
| 7738 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2196 times.
|
2201 | !(usable_tables & cond_func->table_ref->map())) |
| 7739 | 356 | return false; | |
| 7740 | |||
| 7741 | 2196 | TABLE_LIST *tbl = cond_func->table_ref; | |
| 7742 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2194 times.
|
2196 | if (!tbl->table->keys_in_use_for_query.is_set(cond_func->key)) return false; |
| 7743 | |||
| 7744 | 2194 | cond_func->set_simple_expression(simple_match_expr); | |
| 7745 | |||
| 7746 | 4388 | const Key_use keyuse(tbl, cond_func, cond_func->key_item()->used_tables(), | |
| 7747 | cond_func->key, FT_KEYPART, | ||
| 7748 | 0, // optimize | ||
| 7749 | 0, // keypart_map | ||
| 7750 | ~(ha_rows)0, // ref_table_rows | ||
| 7751 | false, // null_rejecting | ||
| 7752 | nullptr, // cond_guard | ||
| 7753 |
1/2✓ Branch 0 taken 2194 times.
✗ Branch 1 not taken.
|
2194 | UINT_MAX); // sj_pred_no |
| 7754 | 2194 | tbl->table->reginfo.join_tab->keys().set_bit(cond_func->key); | |
| 7755 |
1/2✓ Branch 0 taken 2194 times.
✗ Branch 1 not taken.
|
2194 | return keyuse_array->push_back(keyuse); |
| 7756 | } | ||
| 7757 | |||
| 7758 | /** | ||
| 7759 | Compares two keyuse elements. | ||
| 7760 | |||
| 7761 | @param a first Key_use element | ||
| 7762 | @param b second Key_use element | ||
| 7763 | |||
| 7764 | Compare Key_use elements so that they are sorted as follows: | ||
| 7765 | -# By table. | ||
| 7766 | -# By key for each table. | ||
| 7767 | -# By keypart for each key. | ||
| 7768 | -# Const values. | ||
| 7769 | -# Ref_or_null. | ||
| 7770 | |||
| 7771 | @retval true If a < b. | ||
| 7772 | @retval false If a >= b. | ||
| 7773 | */ | ||
| 7774 | 31796346 | static bool sort_keyuse(const Key_use &a, const Key_use &b) { | |
| 7775 |
2/2✓ Branch 0 taken 20214477 times.
✓ Branch 1 taken 11582130 times.
|
31796346 | if (a.table_ref->tableno() != b.table_ref->tableno()) |
| 7776 | 20214477 | return a.table_ref->tableno() < b.table_ref->tableno(); | |
| 7777 |
2/2✓ Branch 0 taken 7992176 times.
✓ Branch 1 taken 3589954 times.
|
11582130 | if (a.key != b.key) return a.key < b.key; |
| 7778 |
2/2✓ Branch 0 taken 699147 times.
✓ Branch 1 taken 2890807 times.
|
3589954 | if (a.keypart != b.keypart) return a.keypart < b.keypart; |
| 7779 | // Place const values before other ones | ||
| 7780 | 2890807 | bool a_const = a.used_tables & ~OUTER_REF_TABLE_BIT; | |
| 7781 | 2890807 | bool b_const = b.used_tables & ~OUTER_REF_TABLE_BIT; | |
| 7782 |
2/2✓ Branch 0 taken 654 times.
✓ Branch 1 taken 2890153 times.
|
2890807 | if (a_const != b_const) return b_const; |
| 7783 | /* Place rows that are not 'OPTIMIZE_REF_OR_NULL' first */ | ||
| 7784 | 2890153 | return (a.optimize & KEY_OPTIMIZE_REF_OR_NULL) < | |
| 7785 | 2890153 | (b.optimize & KEY_OPTIMIZE_REF_OR_NULL); | |
| 7786 | } | ||
| 7787 | |||
| 7788 | /* | ||
| 7789 | Add to Key_field array all 'ref' access candidates within nested join. | ||
| 7790 | |||
| 7791 | This function populates Key_field array with entries generated from the | ||
| 7792 | ON condition of the given nested join, and does the same for nested joins | ||
| 7793 | contained within this nested join. | ||
| 7794 | |||
| 7795 | @param thd session context | ||
| 7796 | @param[in] nested_join_table Nested join pseudo-table to process | ||
| 7797 | @param[in,out] end End of the key field array | ||
| 7798 | @param[in,out] and_level And-level | ||
| 7799 | @param[in,out] sargables Array of found sargable candidates | ||
| 7800 | |||
| 7801 | @returns false if success, true if error | ||
| 7802 | |||
| 7803 | @note | ||
| 7804 | We can add accesses to the tables that are direct children of this nested | ||
| 7805 | join (1), and are not inner tables w.r.t their neighbours (2). | ||
| 7806 | |||
| 7807 | Example for #1 (outer brackets pair denotes nested join this function is | ||
| 7808 | invoked for): | ||
| 7809 | @code | ||
| 7810 | ... LEFT JOIN (t1 LEFT JOIN (t2 ... ) ) ON cond | ||
| 7811 | @endcode | ||
| 7812 | Example for #2: | ||
| 7813 | @code | ||
| 7814 | ... LEFT JOIN (t1 LEFT JOIN t2 ) ON cond | ||
| 7815 | @endcode | ||
| 7816 | In examples 1-2 for condition cond, we can add 'ref' access candidates to | ||
| 7817 | t1 only. | ||
| 7818 | Example #3: | ||
| 7819 | @code | ||
| 7820 | ... LEFT JOIN (t1, t2 LEFT JOIN t3 ON inner_cond) ON cond | ||
| 7821 | @endcode | ||
| 7822 | Here we can add 'ref' access candidates for t1 and t2, but not for t3. | ||
| 7823 | */ | ||
| 7824 | |||
| 7825 | 24256 | static bool add_key_fields_for_nj(THD *thd, JOIN *join, | |
| 7826 | TABLE_LIST *nested_join_table, | ||
| 7827 | Key_field **end, uint *and_level, | ||
| 7828 | SARGABLE_PARAM **sargables) { | ||
| 7829 | 24256 | mem_root_deque<TABLE_LIST *> &join_list = | |
| 7830 | 24256 | nested_join_table->nested_join->join_list; | |
| 7831 |
1/2✓ Branch 0 taken 24256 times.
✗ Branch 1 not taken.
|
24256 | auto li = join_list.begin(); |
| 7832 |
1/2✓ Branch 0 taken 24256 times.
✗ Branch 1 not taken.
|
24256 | auto li_end = join_list.end(); |
| 7833 |
1/2✓ Branch 0 taken 24256 times.
✗ Branch 1 not taken.
|
24256 | auto li2 = join_list.begin(); |
| 7834 |
1/2✓ Branch 0 taken 24256 times.
✗ Branch 1 not taken.
|
24256 | auto li2_end = join_list.end(); |
| 7835 | 24256 | bool have_another = false; | |
| 7836 | 24256 | table_map tables = 0; | |
| 7837 | TABLE_LIST *table; | ||
| 7838 | |||
| 7839 |
9/12✓ Branch 0 taken 71755 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46549 times.
✓ Branch 3 taken 25206 times.
✓ Branch 4 taken 46549 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 46549 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 25206 times.
✓ Branch 9 taken 46549 times.
✓ Branch 10 taken 950 times.
✓ Branch 11 taken 24256 times.
|
72705 | while ((table = (li != li_end) ? *li++ : nullptr) || |
| 7840 |
3/6✓ Branch 0 taken 950 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 950 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 950 times.
✗ Branch 5 not taken.
|
950 | (have_another && li2 != join_list.end() && |
| 7841 | 950 | (li = li2, li_end = li2_end, have_another = false, | |
| 7842 |
7/12✓ Branch 0 taken 950 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 950 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 950 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 950 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 950 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 47499 times.
✓ Branch 11 taken 24256 times.
|
72705 | (li != li_end) && (table = *li++)))) { |
| 7843 |
2/2✓ Branch 0 taken 1347 times.
✓ Branch 1 taken 46152 times.
|
47499 | if (table->nested_join) { |
| 7844 |
2/2✓ Branch 0 taken 950 times.
✓ Branch 1 taken 397 times.
|
1347 | if (!table->join_cond_optim()) { |
| 7845 | /* It's a semi-join nest. Walk into it as if it wasn't a nest */ | ||
| 7846 | 950 | have_another = true; | |
| 7847 | 950 | li2 = li; | |
| 7848 | 950 | li2_end = li_end; | |
| 7849 |
1/2✓ Branch 0 taken 950 times.
✗ Branch 1 not taken.
|
950 | li = table->nested_join->join_list.begin(); |
| 7850 |
1/2✓ Branch 0 taken 950 times.
✗ Branch 1 not taken.
|
950 | li_end = table->nested_join->join_list.end(); |
| 7851 | } else { | ||
| 7852 |
2/4✓ Branch 0 taken 397 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 397 times.
|
397 | if (add_key_fields_for_nj(thd, join, table, end, and_level, sargables)) |
| 7853 | ✗ | return true; | |
| 7854 | } | ||
| 7855 |
2/2✓ Branch 0 taken 40157 times.
✓ Branch 1 taken 5995 times.
|
46152 | } else if (!table->join_cond_optim()) |
| 7856 | 40157 | tables |= table->map(); | |
| 7857 | } | ||
| 7858 |
2/2✓ Branch 0 taken 3477 times.
✓ Branch 1 taken 20779 times.
|
24256 | if (nested_join_table->join_cond_optim()) { |
| 7859 |
2/4✓ Branch 0 taken 3477 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3477 times.
|
3477 | if (add_key_fields(thd, join, end, and_level, |
| 7860 | nested_join_table->join_cond_optim(), tables, sargables)) | ||
| 7861 | ✗ | return true; | |
| 7862 | } | ||
| 7863 | 24256 | return false; | |
| 7864 | } | ||
| 7865 | |||
| 7866 | /// @} (end of group RefOptimizerModule) | ||
| 7867 | |||
| 7868 | /** | ||
| 7869 | Check for the presence of AGGFN(DISTINCT a) queries that may be subject | ||
| 7870 | to loose index scan. | ||
| 7871 | |||
| 7872 | |||
| 7873 | Check if the query is a subject to AGGFN(DISTINCT) using loose index scan | ||
| 7874 | (GroupIndexSkipScanIterator). | ||
| 7875 | Optionally (if out_args is supplied) will push the arguments of | ||
| 7876 | AGGFN(DISTINCT) to the list | ||
| 7877 | |||
| 7878 | Check for every COUNT(DISTINCT), AVG(DISTINCT) or | ||
| 7879 | SUM(DISTINCT). These can be resolved by Loose Index Scan as long | ||
| 7880 | as all the aggregate distinct functions refer to the same | ||
| 7881 | fields. Thus: | ||
| 7882 | |||
| 7883 | SELECT AGGFN(DISTINCT a, b), AGGFN(DISTINCT b, a)... => can use LIS | ||
| 7884 | SELECT AGGFN(DISTINCT a), AGGFN(DISTINCT a) ... => can use LIS | ||
| 7885 | SELECT AGGFN(DISTINCT a, b), AGGFN(DISTINCT a) ... => cannot use LIS | ||
| 7886 | SELECT AGGFN(DISTINCT a), AGGFN(DISTINCT b) ... => cannot use LIS | ||
| 7887 | etc. | ||
| 7888 | |||
| 7889 | @param join the join to check | ||
| 7890 | @param[out] out_args Collect the arguments of the aggregate functions | ||
| 7891 | to a list. We don't worry about duplicates as | ||
| 7892 | these will be sorted out later in | ||
| 7893 | get_best_group_min_max. | ||
| 7894 | |||
| 7895 | @return does the query qualify for indexed AGGFN(DISTINCT) | ||
| 7896 | @retval true it does | ||
| 7897 | @retval false AGGFN(DISTINCT) must apply distinct in it. | ||
| 7898 | */ | ||
| 7899 | |||
| 7900 | 2563780 | bool is_indexed_agg_distinct(JOIN *join, | |
| 7901 | mem_root_deque<Item_field *> *out_args) { | ||
| 7902 | Item_sum **sum_item_ptr; | ||
| 7903 | 2563780 | bool result = false; | |
| 7904 |
1/2✓ Branch 0 taken 2563886 times.
✗ Branch 1 not taken.
|
2563780 | Field_map first_aggdistinct_fields; |
| 7905 | |||
| 7906 |
2/2✓ Branch 0 taken 2125326 times.
✓ Branch 1 taken 438560 times.
|
2563886 | if (join->primary_tables > 1 || /* reference more than 1 table */ |
| 7907 |
2/2✓ Branch 0 taken 2122457 times.
✓ Branch 1 taken 2869 times.
|
2125326 | join->select_distinct || /* or a DISTINCT */ |
| 7908 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2122457 times.
|
2122457 | join->query_block->olap == ROLLUP_TYPE) /* Check (B3) for ROLLUP */ |
| 7909 | 441429 | return false; | |
| 7910 | |||
| 7911 |
2/4✓ Branch 0 taken 2122457 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2122457 times.
|
2122457 | if (join->make_sum_func_list(*join->fields, true)) return false; |
| 7912 | |||
| 7913 |
2/2✓ Branch 0 taken 670704 times.
✓ Branch 1 taken 1483496 times.
|
2154200 | for (sum_item_ptr = join->sum_funcs; *sum_item_ptr; sum_item_ptr++) { |
| 7914 | 670704 | Item_sum *sum_item = *sum_item_ptr; | |
| 7915 |
1/2✓ Branch 0 taken 670704 times.
✗ Branch 1 not taken.
|
670704 | Field_map cur_aggdistinct_fields; |
| 7916 | Item *expr; | ||
| 7917 | /* aggregate is not AGGFN(DISTINCT) or more than 1 argument to it */ | ||
| 7918 |
5/6✓ Branch 0 taken 670704 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30053 times.
✓ Branch 3 taken 1346 times.
✓ Branch 4 taken 539 times.
✓ Branch 5 taken 638766 times.
|
670704 | switch (sum_item->sum_func()) { |
| 7919 | 30053 | case Item_sum::MIN_FUNC: | |
| 7920 | case Item_sum::MAX_FUNC: | ||
| 7921 | 30053 | continue; | |
| 7922 | 1346 | case Item_sum::COUNT_DISTINCT_FUNC: | |
| 7923 | 1346 | break; | |
| 7924 | 539 | case Item_sum::AVG_DISTINCT_FUNC: | |
| 7925 | case Item_sum::SUM_DISTINCT_FUNC: | ||
| 7926 |
2/4✓ Branch 0 taken 539 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 539 times.
✗ Branch 3 not taken.
|
539 | if (sum_item->argument_count() == 1) break; |
| 7927 | [[fallthrough]]; | ||
| 7928 | default: | ||
| 7929 | 638961 | return false; | |
| 7930 | } | ||
| 7931 | |||
| 7932 |
3/4✓ Branch 0 taken 3860 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2134 times.
✓ Branch 3 taken 1726 times.
|
3860 | for (uint i = 0; i < sum_item->argument_count(); i++) { |
| 7933 |
1/2✓ Branch 0 taken 2134 times.
✗ Branch 1 not taken.
|
2134 | expr = sum_item->get_arg(i); |
| 7934 | /* The AGGFN(DISTINCT) arg is not an attribute? */ | ||
| 7935 |
4/6✓ Branch 0 taken 2134 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2134 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 159 times.
✓ Branch 5 taken 1975 times.
|
2134 | if (expr->real_item()->type() != Item::FIELD_ITEM) return false; |
| 7936 | |||
| 7937 |
1/2✓ Branch 0 taken 1975 times.
✗ Branch 1 not taken.
|
1975 | Item_field *item = static_cast<Item_field *>(expr->real_item()); |
| 7938 |
3/4✓ Branch 0 taken 1097 times.
✓ Branch 1 taken 878 times.
✓ Branch 2 taken 1097 times.
✗ Branch 3 not taken.
|
1975 | if (out_args) out_args->push_back(item); |
| 7939 | |||
| 7940 | 1975 | cur_aggdistinct_fields.set_bit(item->field->field_index()); | |
| 7941 | 1975 | result = true; | |
| 7942 | } | ||
| 7943 | /* | ||
| 7944 | If there are multiple aggregate functions, make sure that they all | ||
| 7945 | refer to exactly the same set of columns. | ||
| 7946 | */ | ||
| 7947 |
3/4✓ Branch 0 taken 1726 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1453 times.
✓ Branch 3 taken 273 times.
|
1726 | if (first_aggdistinct_fields.is_clear_all()) |
| 7948 |
1/2✓ Branch 0 taken 1453 times.
✗ Branch 1 not taken.
|
1453 | first_aggdistinct_fields.merge(cur_aggdistinct_fields); |
| 7949 |
3/4✓ Branch 0 taken 273 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 237 times.
|
273 | else if (first_aggdistinct_fields != cur_aggdistinct_fields) |
| 7950 | 36 | return false; | |
| 7951 | } | ||
| 7952 | |||
| 7953 | 1483496 | return result; | |
| 7954 | } | ||
| 7955 | |||
| 7956 | /** | ||
| 7957 | Print keys that were appended to join_tab->const_keys because they | ||
| 7958 | can be used for GROUP BY or DISTINCT to the optimizer trace. | ||
| 7959 | |||
| 7960 | @param trace The optimizer trace context we're adding info to | ||
| 7961 | @param join_tab The table the indexes cover | ||
| 7962 | @param new_keys The keys that are considered useful because they can | ||
| 7963 | be used for GROUP BY or DISTINCT | ||
| 7964 | @param cause Zero-terminated string with reason for adding indexes | ||
| 7965 | to const_keys | ||
| 7966 | |||
| 7967 | @see add_group_and_distinct_keys() | ||
| 7968 | */ | ||
| 7969 | 12507 | static void trace_indexes_added_group_distinct(Opt_trace_context *trace, | |
| 7970 | const JOIN_TAB *join_tab, | ||
| 7971 | const Key_map new_keys, | ||
| 7972 | const char *cause) { | ||
| 7973 |
2/2✓ Branch 0 taken 12424 times.
✓ Branch 1 taken 83 times.
|
12507 | if (likely(!trace->is_started())) return; |
| 7974 | |||
| 7975 | 83 | KEY *key_info = join_tab->table()->key_info; | |
| 7976 | 83 | Key_map existing_keys = join_tab->const_keys; | |
| 7977 | 83 | uint nbrkeys = join_tab->table()->s->keys; | |
| 7978 | |||
| 7979 |
1/2✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
|
83 | Opt_trace_object trace_summary(trace, "const_keys_added"); |
| 7980 | { | ||
| 7981 |
1/2✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
|
83 | Opt_trace_array trace_key(trace, "keys"); |
| 7982 |
2/2✓ Branch 0 taken 125 times.
✓ Branch 1 taken 83 times.
|
208 | for (uint j = 0; j < nbrkeys; j++) |
| 7983 |
6/6✓ Branch 0 taken 111 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 110 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 110 times.
✓ Branch 5 taken 15 times.
|
125 | if (new_keys.is_set(j) && !existing_keys.is_set(j)) |
| 7984 |
1/2✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
|
110 | trace_key.add_utf8(key_info[j].name); |
| 7985 | 83 | } | |
| 7986 |
1/2✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
|
83 | trace_summary.add_alnum("cause", cause); |
| 7987 | 83 | } | |
| 7988 | |||
| 7989 | /** | ||
| 7990 | Discover the indexes that might be used for GROUP BY or DISTINCT queries or | ||
| 7991 | indexes that might be used for SKIP SCAN. | ||
| 7992 | |||
| 7993 | If the query has a GROUP BY clause, find all indexes that contain | ||
| 7994 | all GROUP BY fields, and add those indexes to join_tab->const_keys | ||
| 7995 | and join_tab->keys. | ||
| 7996 | |||
| 7997 | If the query has a DISTINCT clause, find all indexes that contain | ||
| 7998 | all SELECT fields, and add those indexes to join_tab->const_keys and | ||
| 7999 | join_tab->keys. This allows later on such queries to be processed by | ||
| 8000 | a GroupIndexSkipScanIterator. | ||
| 8001 | |||
| 8002 | If the query does not have GROUP BY clause or any aggregate function | ||
| 8003 | the function collects possible keys to use for skip scan access. | ||
| 8004 | |||
| 8005 | Note that indexes that are not usable for resolving GROUP | ||
| 8006 | BY/DISTINCT may also be added in some corner cases. For example, an | ||
| 8007 | index covering 'a' and 'b' is not usable for the following query but | ||
| 8008 | is still added: "SELECT DISTINCT a+b FROM t1". This is not a big | ||
| 8009 | issue because a) although the optimizer will consider using the | ||
| 8010 | index, it will not chose it (so minor calculation cost added but not | ||
| 8011 | wrong result) and b) it applies only to corner cases. | ||
| 8012 | |||
| 8013 | @param join the current join | ||
| 8014 | @param join_tab joined table | ||
| 8015 | */ | ||
| 8016 | |||
| 8017 | 3820856 | static void add_loose_index_scan_and_skip_scan_keys(JOIN *join, | |
| 8018 | JOIN_TAB *join_tab) { | ||
| 8019 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3820898 times.
|
3820856 | assert(join_tab->const_keys.is_subset(join_tab->keys())); |
| 8020 | |||
| 8021 | 3820898 | mem_root_deque<Item_field *> indexed_fields(join->thd->mem_root); | |
| 8022 | ORDER *cur_group; | ||
| 8023 | const char *cause; | ||
| 8024 | |||
| 8025 | /* Find the indexes that might be used for skip scan queries. */ | ||
| 8026 |
1/2✓ Branch 0 taken 3820853 times.
✗ Branch 1 not taken.
|
3820840 | if (hint_table_state(join->thd, join_tab->table_ref, SKIP_SCAN_HINT_ENUM, |
| 8027 | 3817159 | OPTIMIZER_SKIP_SCAN) && | |
| 8028 |
6/6✓ Branch 0 taken 3171714 times.
✓ Branch 1 taken 645445 times.
✓ Branch 2 taken 679114 times.
✓ Branch 3 taken 2492600 times.
✓ Branch 4 taken 664651 times.
✓ Branch 5 taken 14463 times.
|
4496273 | join->where_cond && join->primary_tables == 1 && |
| 8029 | 679114 | join->group_list.empty() && | |
| 8030 |
7/8✓ Branch 0 taken 3817159 times.
✓ Branch 1 taken 3694 times.
✓ Branch 2 taken 664679 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 664525 times.
✓ Branch 5 taken 154 times.
✓ Branch 6 taken 662890 times.
✓ Branch 7 taken 3157991 times.
|
8302537 | !is_indexed_agg_distinct(join, &indexed_fields) && |
| 8031 |
2/2✓ Branch 0 taken 662890 times.
✓ Branch 1 taken 1635 times.
|
664525 | !join->select_distinct) { |
| 8032 |
1/2✓ Branch 0 taken 662890 times.
✗ Branch 1 not taken.
|
662890 | join->where_cond->walk(&Item::collect_item_field_processor, |
| 8033 | enum_walk::POSTFIX, (uchar *)&indexed_fields); | ||
| 8034 |
1/2✓ Branch 0 taken 662890 times.
✗ Branch 1 not taken.
|
662890 | Key_map possible_keys; |
| 8035 | 662890 | possible_keys.set_all(); | |
| 8036 | 662890 | join_tab->skip_scan_keys.clear_all(); | |
| 8037 |
7/12✓ Branch 0 taken 662890 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 662890 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 910668 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 906464 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1569354 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 910668 times.
✓ Branch 11 taken 658686 times.
|
1569354 | for (Item_field *cur_item : indexed_fields) { |
| 8038 |
3/4✓ Branch 0 taken 910668 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4204 times.
✓ Branch 3 taken 906464 times.
|
910668 | if (cur_item->used_tables() != join_tab->table_ref->map()) return; |
| 8039 | 906464 | possible_keys.intersect(cur_item->field->part_of_key); | |
| 8040 | } | ||
| 8041 | 658686 | join_tab->skip_scan_keys.merge(possible_keys); | |
| 8042 | 658686 | cause = "skip_scan"; | |
| 8043 | 658686 | return; | |
| 8044 | } | ||
| 8045 | |||
| 8046 |
2/2✓ Branch 0 taken 32964 times.
✓ Branch 1 taken 3125050 times.
|
3157991 | if (!join->group_list.empty()) { |
| 8047 | /* Collect all query fields referenced in the GROUP clause. */ | ||
| 8048 |
2/2✓ Branch 0 taken 57202 times.
✓ Branch 1 taken 32964 times.
|
90166 | for (cur_group = join->group_list.order; cur_group; |
| 8049 | 57202 | cur_group = cur_group->next) | |
| 8050 | 57202 | (*cur_group->item) | |
| 8051 |
1/2✓ Branch 0 taken 57202 times.
✗ Branch 1 not taken.
|
57202 | ->walk(&Item::collect_item_field_processor, enum_walk::POSTFIX, |
| 8052 | (uchar *)&indexed_fields); | ||
| 8053 | 32964 | cause = "group_by"; | |
| 8054 |
2/2✓ Branch 0 taken 7919 times.
✓ Branch 1 taken 3117131 times.
|
3125050 | } else if (join->select_distinct) { |
| 8055 | /* Collect all query fields referenced in the SELECT clause. */ | ||
| 8056 |
8/14✓ Branch 0 taken 7919 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7919 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7919 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 28837 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 28837 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 36756 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 28837 times.
✓ Branch 13 taken 7919 times.
|
36756 | for (Item *item : VisibleFields(*join->fields)) { |
| 8057 |
1/2✓ Branch 0 taken 28837 times.
✗ Branch 1 not taken.
|
28837 | item->walk(&Item::collect_item_field_processor, enum_walk::POSTFIX, |
| 8058 | (uchar *)&indexed_fields); | ||
| 8059 | } | ||
| 8060 | 7919 | cause = "distinct"; | |
| 8061 |
4/4✓ Branch 0 taken 292773 times.
✓ Branch 1 taken 2824358 times.
✓ Branch 2 taken 324 times.
✓ Branch 3 taken 3116807 times.
|
3409904 | } else if (join->tmp_table_param.sum_func_count && |
| 8062 |
3/4✓ Branch 0 taken 292773 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 324 times.
✓ Branch 3 taken 292449 times.
|
292773 | is_indexed_agg_distinct(join, &indexed_fields)) { |
| 8063 | /* | ||
| 8064 | SELECT list with AGGFN(distinct col). The query qualifies for | ||
| 8065 | loose index scan, and is_indexed_agg_distinct() has already | ||
| 8066 | collected all referenced fields into indexed_fields. | ||
| 8067 | */ | ||
| 8068 | 324 | join->streaming_aggregation = true; | |
| 8069 | 324 | cause = "indexed_distinct_aggregate"; | |
| 8070 | } else | ||
| 8071 | 3116807 | return; | |
| 8072 | |||
| 8073 |
3/4✓ Branch 0 taken 41207 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 315 times.
✓ Branch 3 taken 40892 times.
|
41207 | if (indexed_fields.empty()) return; |
| 8074 | |||
| 8075 | 40892 | Key_map possible_keys = join_tab->table()->keys_in_use_for_query; | |
| 8076 | 40892 | possible_keys.merge(join_tab->table()->keys_in_use_for_group_by); | |
| 8077 | |||
| 8078 | /* Intersect the keys of all group fields. */ | ||
| 8079 |
7/12✓ Branch 0 taken 40892 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40892 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 49609 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 34959 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 75851 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 49609 times.
✓ Branch 11 taken 26242 times.
|
75851 | for (Item_field *cur_item : indexed_fields) { |
| 8080 |
3/4✓ Branch 0 taken 49609 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14650 times.
✓ Branch 3 taken 34959 times.
|
49609 | if (cur_item->used_tables() != join_tab->table_ref->map()) { |
| 8081 | /* | ||
| 8082 | Doing GROUP BY or DISTINCT on a field in another table so no | ||
| 8083 | index in this table is usable | ||
| 8084 | */ | ||
| 8085 | 14650 | return; | |
| 8086 | } else | ||
| 8087 | 34959 | possible_keys.intersect(cur_item->field->part_of_key); | |
| 8088 | } | ||
| 8089 | |||
| 8090 | /* | ||
| 8091 | At this point, possible_keys has key bits set only for usable | ||
| 8092 | indexes because indexed_fields is non-empty and if any of the | ||
| 8093 | fields belong to a different table the function would exit in the | ||
| 8094 | loop above. | ||
| 8095 | */ | ||
| 8096 | |||
| 8097 |
4/4✓ Branch 0 taken 14026 times.
✓ Branch 1 taken 12216 times.
✓ Branch 2 taken 12507 times.
✓ Branch 3 taken 13735 times.
|
40268 | if (!possible_keys.is_clear_all() && |
| 8098 |
2/2✓ Branch 0 taken 12507 times.
✓ Branch 1 taken 1519 times.
|
14026 | !possible_keys.is_subset(join_tab->const_keys)) { |
| 8099 |
1/2✓ Branch 0 taken 12507 times.
✗ Branch 1 not taken.
|
12507 | trace_indexes_added_group_distinct(&join->thd->opt_trace, join_tab, |
| 8100 | possible_keys, cause); | ||
| 8101 | 12507 | join_tab->const_keys.merge(possible_keys); | |
| 8102 | 12507 | join_tab->keys().merge(possible_keys); | |
| 8103 | } | ||
| 8104 | |||
| 8105 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26242 times.
|
26242 | assert(join_tab->const_keys.is_subset(join_tab->keys())); |
| 8106 |
2/2✓ Branch 0 taken 26242 times.
✓ Branch 1 taken 3794610 times.
|
3820904 | } |
| 8107 | |||
| 8108 | /** | ||
| 8109 | Update keyuse array with all possible keys we can use to fetch rows. | ||
| 8110 | |||
| 8111 | @param thd session context | ||
| 8112 | @param[out] keyuse Put here ordered array of Key_use structures | ||
| 8113 | @param join_tab Array in table number order | ||
| 8114 | @param tables Number of tables in join | ||
| 8115 | @param cond WHERE condition (note that the function analyzes | ||
| 8116 | join_tab[i]->join_cond() too) | ||
| 8117 | @param normal_tables Tables not inner w.r.t some outer join (ones | ||
| 8118 | for which we can make ref access based the WHERE | ||
| 8119 | clause) | ||
| 8120 | @param query_block current SELECT | ||
| 8121 | @param[out] sargables Array of found sargable candidates | ||
| 8122 | |||
| 8123 | @returns false if success, true if error | ||
| 8124 | */ | ||
| 8125 | |||
| 8126 | 1240771 | static bool update_ref_and_keys(THD *thd, Key_use_array *keyuse, | |
| 8127 | JOIN_TAB *join_tab, uint tables, Item *cond, | ||
| 8128 | table_map normal_tables, | ||
| 8129 | Query_block *query_block, | ||
| 8130 | SARGABLE_PARAM **sargables) { | ||
| 8131 |
4/6✓ Branch 0 taken 1235118 times.
✓ Branch 1 taken 5653 times.
✓ Branch 2 taken 1235175 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1235175 times.
|
1240771 | assert(cond == nullptr || cond->is_bool_func()); |
| 8132 | uint and_level, i; | ||
| 8133 | Key_field *key_fields, *end, *field; | ||
| 8134 | size_t sz; | ||
| 8135 | 1240828 | uint m = max(query_block->max_equal_elems, 1U); | |
| 8136 | 1240827 | JOIN *const join = query_block->join; | |
| 8137 | /* | ||
| 8138 | We use the same piece of memory to store both Key_field | ||
| 8139 | and SARGABLE_PARAM structure. | ||
| 8140 | Key_field values are placed at the beginning this memory | ||
| 8141 | while SARGABLE_PARAM values are put at the end. | ||
| 8142 | All predicates that are used to fill arrays of Key_field | ||
| 8143 | and SARGABLE_PARAM structures have at most 2 arguments | ||
| 8144 | except BETWEEN predicates that have 3 arguments and | ||
| 8145 | IN predicates. | ||
| 8146 | This any predicate if it's not BETWEEN/IN can be used | ||
| 8147 | directly to fill at most 2 array elements, either of Key_field | ||
| 8148 | or SARGABLE_PARAM type. For a BETWEEN predicate 3 elements | ||
| 8149 | can be filled as this predicate is considered as | ||
| 8150 | saragable with respect to each of its argument. | ||
| 8151 | An IN predicate can require at most 1 element as currently | ||
| 8152 | it is considered as sargable only for its first argument. | ||
| 8153 | Multiple equality can add elements that are filled after | ||
| 8154 | substitution of field arguments by equal fields. There | ||
| 8155 | can be not more than query_block->max_equal_elems such | ||
| 8156 | substitutions. | ||
| 8157 | */ | ||
| 8158 | 1240827 | sz = max(sizeof(Key_field), sizeof(SARGABLE_PARAM)) * | |
| 8159 | 1240807 | (((query_block->cond_count + 1) * 2 + query_block->between_count) * m + | |
| 8160 | 1); | ||
| 8161 |
2/4✓ Branch 0 taken 1240822 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1240822 times.
|
1240807 | if (!(key_fields = (Key_field *)thd->alloc(sz))) |
| 8162 | ✗ | return true; /* purecov: inspected */ | |
| 8163 | 1240822 | and_level = 0; | |
| 8164 | 1240822 | field = end = key_fields; | |
| 8165 | 1240822 | *sargables = (SARGABLE_PARAM *)key_fields + | |
| 8166 | 1240822 | (sz - sizeof((*sargables)[0].field)) / sizeof(SARGABLE_PARAM); | |
| 8167 | /* set a barrier for the array of SARGABLE_PARAM */ | ||
| 8168 | 1240822 | (*sargables)[0].field = nullptr; | |
| 8169 | |||
| 8170 |
2/2✓ Branch 0 taken 1235182 times.
✓ Branch 1 taken 5640 times.
|
1240822 | if (cond) { |
| 8171 |
2/4✓ Branch 0 taken 1235191 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1235191 times.
|
1235182 | if (add_key_fields(thd, join, &end, &and_level, cond, normal_tables, |
| 8172 | sargables)) | ||
| 8173 | ✗ | return true; | |
| 8174 | |||
| 8175 | // The relevant secondary engines don't support antijoin, so don't enable | ||
| 8176 | // this optimization for them. | ||
| 8177 |
2/2✓ Branch 0 taken 1235072 times.
✓ Branch 1 taken 119 times.
|
1235191 | if (thd->secondary_engine_optimization() != |
| 8178 | Secondary_engine_optimization::SECONDARY) { | ||
| 8179 |
2/2✓ Branch 0 taken 3784092 times.
✓ Branch 1 taken 1235054 times.
|
5019146 | for (Key_field *fld = field; fld != end; fld++) { |
| 8180 | /* Mark that we can optimize LEFT JOIN */ | ||
| 8181 |
5/6✓ Branch 0 taken 3784074 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3099 times.
✓ Branch 3 taken 3780975 times.
✓ Branch 4 taken 471 times.
✓ Branch 5 taken 3783603 times.
|
3787191 | if (fld->val->type() == Item::NULL_ITEM && |
| 8182 |
2/2✓ Branch 0 taken 471 times.
✓ Branch 1 taken 2628 times.
|
3099 | !fld->item_field->field->is_nullable()) { |
| 8183 | /* | ||
| 8184 | Example: | ||
| 8185 | SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a WHERE t2.a IS NULL; | ||
| 8186 | this just wants rows of t1 where t1.a does not exist in t2. | ||
| 8187 | */ | ||
| 8188 | 471 | fld->item_field->field->table->reginfo.not_exists_optimize = true; | |
| 8189 | } | ||
| 8190 | } | ||
| 8191 | } | ||
| 8192 | } | ||
| 8193 | |||
| 8194 |
2/2✓ Branch 0 taken 3310873 times.
✓ Branch 1 taken 1240849 times.
|
4551722 | for (i = 0; i < tables; i++) { |
| 8195 | /* | ||
| 8196 | Block the creation of keys for inner tables of outer joins. | ||
| 8197 | Here only the outer joins that can not be converted to | ||
| 8198 | inner joins are left and all nests that can be eliminated | ||
| 8199 | are flattened. | ||
| 8200 | In the future when we introduce conditional accesses | ||
| 8201 | for inner tables in outer joins these keys will be taken | ||
| 8202 | into account as well. | ||
| 8203 | */ | ||
| 8204 |
2/2✓ Branch 0 taken 526892 times.
✓ Branch 1 taken 2783988 times.
|
3310873 | if (join_tab[i].join_cond()) { |
| 8205 |
2/4✓ Branch 0 taken 526921 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 526921 times.
|
526902 | if (add_key_fields(thd, join, &end, &and_level, join_tab[i].join_cond(), |
| 8206 | 526892 | join_tab[i].table_ref->map(), sargables)) | |
| 8207 | ✗ | return true; | |
| 8208 | } | ||
| 8209 | } | ||
| 8210 | |||
| 8211 | /* Process ON conditions for the nested joins */ | ||
| 8212 |
7/12✓ Branch 0 taken 1240829 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1240851 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3288669 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3288673 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4529514 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3288669 times.
✓ Branch 11 taken 1240845 times.
|
4529518 | for (TABLE_LIST *tl : query_block->top_join_list) { |
| 8213 |
3/4✓ Branch 0 taken 23859 times.
✓ Branch 1 taken 3264810 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3288669 times.
|
3312528 | if (tl->nested_join && |
| 8214 |
2/4✓ Branch 0 taken 23859 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23859 times.
|
23859 | add_key_fields_for_nj(thd, join, tl, &end, &and_level, sargables)) |
| 8215 | ✗ | return true; | |
| 8216 | } | ||
| 8217 | |||
| 8218 | /* Generate keys descriptions for derived tables */ | ||
| 8219 |
2/2✓ Branch 0 taken 2413 times.
✓ Branch 1 taken 1238432 times.
|
1240845 | if (query_block->materialized_derived_table_count) { |
| 8220 |
2/4✓ Branch 0 taken 2413 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2413 times.
|
2413 | if (join->generate_derived_keys()) return true; |
| 8221 | } | ||
| 8222 | /* fill keyuse with found key parts */ | ||
| 8223 |
2/2✓ Branch 0 taken 4462977 times.
✓ Branch 1 taken 1240850 times.
|
5703827 | for (; field != end; field++) { |
| 8224 |
2/4✓ Branch 0 taken 4462982 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4462982 times.
|
4462977 | if (add_key_part(keyuse, field)) return true; |
| 8225 | } | ||
| 8226 | |||
| 8227 |
2/2✓ Branch 0 taken 2254 times.
✓ Branch 1 taken 1238596 times.
|
1240850 | if (query_block->ftfunc_list->elements) { |
| 8228 |
2/4✓ Branch 0 taken 2254 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2254 times.
|
2254 | if (add_ft_keys(keyuse, cond, normal_tables, true)) return true; |
| 8229 | } | ||
| 8230 | |||
| 8231 | /* | ||
| 8232 | Sort the array of possible keys and remove the following key parts: | ||
| 8233 | - ref if there is a keypart which is a ref and a const. | ||
| 8234 | (e.g. if there is a key(a,b) and the clause is a=3 and b=7 and b=t2.d, | ||
| 8235 | then we skip the key part corresponding to b=t2.d) | ||
| 8236 | - keyparts without previous keyparts | ||
| 8237 | (e.g. if there is a key(a,b,c) but only b < 5 (or a=2 and c < 3) is | ||
| 8238 | used in the query, we drop the partial key parts from consideration). | ||
| 8239 | Special treatment for ft-keys. | ||
| 8240 | */ | ||
| 8241 |
3/4✓ Branch 0 taken 1240830 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 591892 times.
✓ Branch 3 taken 648938 times.
|
1240850 | if (!keyuse->empty()) { |
| 8242 | Key_use *save_pos, *use; | ||
| 8243 | |||
| 8244 |
1/2✓ Branch 0 taken 591887 times.
✗ Branch 1 not taken.
|
591892 | std::sort(keyuse->begin(), keyuse->begin() + keyuse->size(), sort_keyuse); |
| 8245 | |||
| 8246 | const Key_use key_end(nullptr, nullptr, 0, 0, 0, 0, 0, 0, false, nullptr, | ||
| 8247 | 591887 | 0); | |
| 8248 |
2/4✓ Branch 0 taken 591861 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 591861 times.
|
591888 | if (keyuse->push_back(key_end)) // added for easy testing |
| 8249 | ✗ | return true; | |
| 8250 | |||
| 8251 | 591861 | use = save_pos = keyuse->begin(); | |
| 8252 | 591881 | const Key_use *prev = &key_end; | |
| 8253 | 591881 | bool found_eq_constant = false; | |
| 8254 |
2/2✓ Branch 0 taken 6588123 times.
✓ Branch 1 taken 591882 times.
|
7180050 | for (i = 0; i < keyuse->size() - 1; i++, use++) { |
| 8255 | 6588123 | TABLE *const table = use->table_ref->table; | |
| 8256 |
5/6✓ Branch 0 taken 6588184 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 704636 times.
✓ Branch 3 taken 5883548 times.
✓ Branch 4 taken 704394 times.
✓ Branch 5 taken 5883790 times.
|
7292759 | if (use->val->const_for_execution() && |
| 8257 |
2/2✓ Branch 0 taken 704395 times.
✓ Branch 1 taken 241 times.
|
704636 | use->optimize != KEY_OPTIMIZE_REF_OR_NULL) |
| 8258 | 704394 | table->const_key_parts[use->key] |= use->keypart_map; | |
| 8259 |
2/2✓ Branch 0 taken 6585966 times.
✓ Branch 1 taken 2218 times.
|
6588184 | if (use->keypart != FT_KEYPART) { |
| 8260 |
4/4✓ Branch 0 taken 2214068 times.
✓ Branch 1 taken 4371898 times.
✓ Branch 2 taken 1070458 times.
✓ Branch 3 taken 1143610 times.
|
6585966 | if (use->key == prev->key && use->table_ref == prev->table_ref) { |
| 8261 |
2/2✓ Branch 0 taken 1069806 times.
✓ Branch 1 taken 652 times.
|
1070458 | if (prev->keypart + 1 < use->keypart || |
| 8262 |
4/4✓ Branch 0 taken 413423 times.
✓ Branch 1 taken 656383 times.
✓ Branch 2 taken 124 times.
✓ Branch 3 taken 413299 times.
|
1069806 | (prev->keypart == use->keypart && found_eq_constant)) |
| 8263 | 776 | continue; /* remove */ | |
| 8264 |
2/2✓ Branch 0 taken 1846965 times.
✓ Branch 1 taken 3668543 times.
|
5515508 | } else if (use->keypart != 0) // First found must be 0 |
| 8265 | 1846965 | continue; | |
| 8266 | } | ||
| 8267 | |||
| 8268 | /* | ||
| 8269 | Protect against self assignment. | ||
| 8270 | The compiler *may* generate a call to memcpy() to do the assignment, | ||
| 8271 | and that is undefined behaviour (memory overlap). | ||
| 8272 | */ | ||
| 8273 |
2/2✓ Branch 0 taken 2581864 times.
✓ Branch 1 taken 2158579 times.
|
4740443 | if (save_pos != use) *save_pos = *use; |
| 8274 | 4740443 | prev = use; | |
| 8275 |
1/2✓ Branch 0 taken 4740478 times.
✗ Branch 1 not taken.
|
4740443 | found_eq_constant = use->val->const_for_execution(); |
| 8276 | /* Save ptr to first use */ | ||
| 8277 |
2/2✓ Branch 0 taken 2513086 times.
✓ Branch 1 taken 2227398 times.
|
4740478 | if (!table->reginfo.join_tab->keyuse()) |
| 8278 | 2513086 | table->reginfo.join_tab->set_keyuse(save_pos); | |
| 8279 | 4740479 | table->reginfo.join_tab->checked_keys.set_bit(use->key); | |
| 8280 | 4740428 | save_pos++; | |
| 8281 | } | ||
| 8282 | 591882 | i = (uint)(save_pos - keyuse->begin()); | |
| 8283 | 591905 | keyuse->at(i) = key_end; | |
| 8284 | 591891 | keyuse->chop(i); | |
| 8285 | } | ||
| 8286 |
1/2✓ Branch 0 taken 1240828 times.
✗ Branch 1 not taken.
|
1240832 | print_keyuse_array(thd, &thd->opt_trace, keyuse); |
| 8287 | /* | ||
| 8288 | Number of functions here call val_x() methods, which might throw an error. | ||
| 8289 | Catch those errors here. | ||
| 8290 | */ | ||
| 8291 |
1/2✓ Branch 0 taken 1240843 times.
✗ Branch 1 not taken.
|
1240828 | return thd->is_error(); |
| 8292 | } | ||
| 8293 | |||
| 8294 | /** | ||
| 8295 | Create a keyuse array for a table with a primary key. | ||
| 8296 | To be used when creating a materialized temporary table. | ||
| 8297 | |||
| 8298 | @param thd THD pointer, for memory allocation | ||
| 8299 | @param keyparts Number of key parts in the primary key | ||
| 8300 | @param fields fields | ||
| 8301 | @param outer_exprs List of items used for key lookup | ||
| 8302 | |||
| 8303 | @return Pointer to created keyuse array, or NULL if error | ||
| 8304 | */ | ||
| 8305 | 4591 | Key_use_array *create_keyuse_for_table( | |
| 8306 | THD *thd, uint keyparts, Item_field **fields, | ||
| 8307 | const mem_root_deque<Item *> &outer_exprs) { | ||
| 8308 |
1/2✓ Branch 0 taken 4591 times.
✗ Branch 1 not taken.
|
4591 | void *mem = thd->alloc(sizeof(Key_use_array)); |
| 8309 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4591 times.
|
4591 | if (!mem) return nullptr; |
| 8310 |
1/2✓ Branch 0 taken 4591 times.
✗ Branch 1 not taken.
|
4591 | Key_use_array *keyuses = new (mem) Key_use_array(thd->mem_root); |
| 8311 | |||
| 8312 |
1/2✓ Branch 0 taken 4591 times.
✗ Branch 1 not taken.
|
4591 | auto outer_expr_it = outer_exprs.begin(); |
| 8313 | |||
| 8314 |
2/2✓ Branch 0 taken 4973 times.
✓ Branch 1 taken 4591 times.
|
9564 | for (uint keypartno = 0; keypartno < keyparts; keypartno++) { |
| 8315 |
2/4✓ Branch 0 taken 4973 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4973 times.
✗ Branch 3 not taken.
|
4973 | Item *const item = *outer_expr_it++; |
| 8316 | 4973 | Key_field key_field(fields[keypartno], item, 0, 0, true, | |
| 8317 | // null_rejecting must be true for field items only, | ||
| 8318 | // add_not_null_conds() is incapable of handling | ||
| 8319 | // other item types. | ||
| 8320 |
1/2✓ Branch 0 taken 4973 times.
✗ Branch 1 not taken.
|
4973 | (item->type() == Item::FIELD_ITEM), nullptr, UINT_MAX); |
| 8321 |
2/4✓ Branch 0 taken 4973 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4973 times.
|
4973 | if (add_key_part(keyuses, &key_field)) return nullptr; |
| 8322 | } | ||
| 8323 | 4591 | const Key_use key_end(nullptr, nullptr, 0, 0, 0, 0, 0, 0, false, nullptr, 0); | |
| 8324 |
2/4✓ Branch 0 taken 4591 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4591 times.
|
4591 | if (keyuses->push_back(key_end)) // added for easy testing |
| 8325 | ✗ | return nullptr; | |
| 8326 | |||
| 8327 | 4591 | return keyuses; | |
| 8328 | } | ||
| 8329 | |||
| 8330 | /** | ||
| 8331 | Move const tables first in the position array. | ||
| 8332 | |||
| 8333 | Increment the number of const tables and set same basic properties for the | ||
| 8334 | const table. | ||
| 8335 | A const table looked up by a key has type JT_CONST. | ||
| 8336 | A const table with a single row has type JT_SYSTEM. | ||
| 8337 | |||
| 8338 | @param tab Table that is designated as a const table | ||
| 8339 | @param key The key definition to use for this table (NULL if table scan) | ||
| 8340 | */ | ||
| 8341 | |||
| 8342 | 140457 | void JOIN::mark_const_table(JOIN_TAB *tab, Key_use *key) { | |
| 8343 | 140457 | POSITION *const position = positions + const_tables; | |
| 8344 | 140457 | position->table = tab; | |
| 8345 | 140457 | position->key = key; | |
| 8346 | 140457 | position->rows_fetched = 1.0; // This is a const table | |
| 8347 | 140457 | position->filter_effect = 1.0; | |
| 8348 | 140457 | position->prefix_rowcount = 1.0; | |
| 8349 | 140457 | position->read_cost = 0.0; | |
| 8350 | 140457 | position->ref_depend_map = 0; | |
| 8351 | 140457 | position->loosescan_key = MAX_KEY; // Not a LooseScan | |
| 8352 | 140457 | position->sj_strategy = SJ_OPT_NONE; | |
| 8353 | 140457 | positions->use_join_buffer = false; | |
| 8354 | |||
| 8355 | // Move the const table as far down as possible in best_ref | ||
| 8356 | 140457 | JOIN_TAB **pos = best_ref + const_tables + 1; | |
| 8357 |
2/2✓ Branch 0 taken 37266 times.
✓ Branch 1 taken 140457 times.
|
177723 | for (JOIN_TAB *next = best_ref[const_tables]; next != tab; pos++) { |
| 8358 | 37266 | JOIN_TAB *const tmp = pos[0]; | |
| 8359 | 37266 | pos[0] = next; | |
| 8360 | 37266 | next = tmp; | |
| 8361 | } | ||
| 8362 | 140457 | best_ref[const_tables] = tab; | |
| 8363 | |||
| 8364 |
2/2✓ Branch 0 taken 81375 times.
✓ Branch 1 taken 59082 times.
|
140457 | tab->set_type(key ? JT_CONST : JT_SYSTEM); |
| 8365 | |||
| 8366 | 140457 | const_table_map |= tab->table_ref->map(); | |
| 8367 | |||
| 8368 | 140457 | const_tables++; | |
| 8369 | 140457 | } | |
| 8370 | |||
| 8371 | 195165 | void JOIN::make_outerjoin_info() { | |
| 8372 |
1/2✓ Branch 0 taken 195257 times.
✗ Branch 1 not taken.
|
195165 | DBUG_TRACE; |
| 8373 | |||
| 8374 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 195257 times.
|
195257 | assert(query_block->outer_join); |
| 8375 |
4/6✓ Branch 0 taken 195234 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 195237 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 195241 times.
✗ Branch 5 not taken.
|
195257 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 8376 | |||
| 8377 |
1/2✓ Branch 0 taken 195268 times.
✗ Branch 1 not taken.
|
195264 | query_block->reset_nj_counters(); |
| 8378 | |||
| 8379 |
2/2✓ Branch 0 taken 1517055 times.
✓ Branch 1 taken 195358 times.
|
1712413 | for (uint i = const_tables; i < tables; ++i) { |
| 8380 | 1517055 | JOIN_TAB *const tab = best_ref[i]; | |
| 8381 | 1517055 | TABLE *const table = tab->table(); | |
| 8382 |
2/2✓ Branch 0 taken 306795 times.
✓ Branch 1 taken 1210379 times.
|
1517174 | if (!table) continue; |
| 8383 | |||
| 8384 | 1210379 | TABLE_LIST *const tbl = tab->table_ref; | |
| 8385 | /* | ||
| 8386 | If 'tbl' is inside a SJ/AJ nest served by materialization, we must | ||
| 8387 | limit setting first_inner, last_inner and first_upper for join nests | ||
| 8388 | inside the materialized table. Indeed it is the SJ-tmp table, and not | ||
| 8389 | 'tbl', which interacts with the nests outer to the SJ/AJ nest. | ||
| 8390 | */ | ||
| 8391 | const bool sj_mat_inner = | ||
| 8392 |
1/2✓ Branch 0 taken 1210427 times.
✗ Branch 1 not taken.
|
1210379 | sj_is_materialize_strategy(tab->get_sj_strategy()); |
| 8393 | |||
| 8394 |
2/2✓ Branch 0 taken 526679 times.
✓ Branch 1 taken 683751 times.
|
1210430 | if (tbl->outer_join) { |
| 8395 | /* | ||
| 8396 | Table tab is the only one inner table for outer join. | ||
| 8397 | (Like table t4 for the table reference t3 LEFT JOIN t4 ON t3.a=t4.a | ||
| 8398 | is in the query above.) | ||
| 8399 | */ | ||
| 8400 | 526679 | tab->set_last_inner(i); | |
| 8401 | 526661 | tab->set_first_inner(i); | |
| 8402 |
1/2✓ Branch 0 taken 526669 times.
✗ Branch 1 not taken.
|
526667 | tab->init_join_cond_ref(tbl); |
| 8403 | 526669 | tab->cond_equal = tbl->cond_equal; | |
| 8404 | /* | ||
| 8405 | If this outer join nest is embedded in another join nest, | ||
| 8406 | link the join-tabs: | ||
| 8407 | */ | ||
| 8408 | 526669 | TABLE_LIST *const outer_join_nest = tbl->outer_join_nest(); | |
| 8409 |
2/2✓ Branch 0 taken 679 times.
✓ Branch 1 taken 525996 times.
|
526675 | if (outer_join_nest) { |
| 8410 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 679 times.
|
679 | assert(outer_join_nest->nested_join->first_nested != NO_PLAN_IDX); |
| 8411 |
4/4✓ Branch 0 taken 35 times.
✓ Branch 1 taken 644 times.
✓ Branch 2 taken 646 times.
✓ Branch 3 taken 33 times.
|
714 | if (!sj_mat_inner || |
| 8412 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 33 times.
|
35 | (tab->emb_sj_nest->sj_inner_tables & |
| 8413 | 35 | best_ref[outer_join_nest->nested_join->first_nested] | |
| 8414 | 35 | ->table_ref->map())) | |
| 8415 | 646 | tab->set_first_upper(outer_join_nest->nested_join->first_nested); | |
| 8416 | } | ||
| 8417 | } | ||
| 8418 |
2/2✓ Branch 0 taken 21388 times.
✓ Branch 1 taken 1203180 times.
|
1224568 | for (TABLE_LIST *embedding = tbl->embedding; embedding; |
| 8419 | 14218 | embedding = embedding->embedding) { | |
| 8420 | // When reaching the outer tables of the materialized temporary table, | ||
| 8421 | // the decoration for this table is complete. | ||
| 8422 |
4/4✓ Branch 0 taken 3293 times.
✓ Branch 1 taken 18095 times.
✓ Branch 2 taken 3192 times.
✓ Branch 3 taken 101 times.
|
21388 | if (sj_mat_inner && embedding == tab->emb_sj_nest) break; |
| 8423 | // Ignore join nests that are not outer join nests: | ||
| 8424 |
2/2✓ Branch 0 taken 10743 times.
✓ Branch 1 taken 7453 times.
|
18196 | if (!embedding->join_cond_optim()) continue; |
| 8425 | 7453 | NESTED_JOIN *const nested_join = embedding->nested_join; | |
| 8426 |
2/2✓ Branch 0 taken 3475 times.
✓ Branch 1 taken 3978 times.
|
7453 | if (!nested_join->nj_counter) { |
| 8427 | /* | ||
| 8428 | Table tab is the first inner table for nested_join. | ||
| 8429 | Save reference to it in the nested join structure. | ||
| 8430 | */ | ||
| 8431 | 3475 | nested_join->first_nested = i; | |
| 8432 | // The table's condition is set to point to the join nest's condition | ||
| 8433 |
1/2✓ Branch 0 taken 3475 times.
✗ Branch 1 not taken.
|
3475 | tab->init_join_cond_ref(embedding); |
| 8434 | 3475 | tab->cond_equal = tbl->cond_equal; | |
| 8435 | |||
| 8436 | 3475 | TABLE_LIST *const outer_join_nest = embedding->outer_join_nest(); | |
| 8437 |
2/2✓ Branch 0 taken 198 times.
✓ Branch 1 taken 3277 times.
|
3475 | if (outer_join_nest) { |
| 8438 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
|
198 | assert(outer_join_nest->nested_join->first_nested != NO_PLAN_IDX); |
| 8439 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 192 times.
✓ Branch 3 taken 6 times.
|
204 | if (!sj_mat_inner || |
| 8440 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | (tab->emb_sj_nest->sj_inner_tables & |
| 8441 | 6 | best_ref[outer_join_nest->nested_join->first_nested] | |
| 8442 | 6 | ->table_ref->map())) | |
| 8443 | 192 | tab->set_first_upper(outer_join_nest->nested_join->first_nested); | |
| 8444 | } | ||
| 8445 | } | ||
| 8446 |
2/2✓ Branch 0 taken 6615 times.
✓ Branch 1 taken 838 times.
|
7453 | if (tab->first_inner() == NO_PLAN_IDX) |
| 8447 | 6615 | tab->set_first_inner(nested_join->first_nested); | |
| 8448 | /* | ||
| 8449 | If including the sj-mat tmp table, this also implicitly | ||
| 8450 | includes the inner tables of the sj-nest. | ||
| 8451 | */ | ||
| 8452 | 7453 | nested_join->nj_counter += | |
| 8453 |
2/2✓ Branch 0 taken 335 times.
✓ Branch 1 taken 7118 times.
|
7453 | tab->sj_mat_exec() ? tab->sj_mat_exec()->table_count : 1; |
| 8454 |
2/2✓ Branch 0 taken 3978 times.
✓ Branch 1 taken 3475 times.
|
7453 | if (nested_join->nj_counter < nested_join->nj_total) break; |
| 8455 | // Table tab is the last inner table for nested join. | ||
| 8456 | 3475 | best_ref[nested_join->first_nested]->set_last_inner(i); | |
| 8457 | } | ||
| 8458 | } | ||
| 8459 | 195358 | } | |
| 8460 | |||
| 8461 | /** | ||
| 8462 | Build a condition guarded by match variables for embedded outer joins. | ||
| 8463 | When generating a condition for a table as part of an outer join condition | ||
| 8464 | or the WHERE condition, the table in question may also be part of an | ||
| 8465 | embedded outer join. In such cases, the condition must be guarded by | ||
| 8466 | the match variable for this embedded outer join. Such embedded outer joins | ||
| 8467 | may also be recursively embedded in other joins. | ||
| 8468 | |||
| 8469 | The function recursively adds guards for a condition ascending from tab | ||
| 8470 | to root_tab, which is the first inner table of an outer join, | ||
| 8471 | or NULL if the condition being handled is the WHERE clause. | ||
| 8472 | |||
| 8473 | @param join the current join | ||
| 8474 | @param idx index of the first inner table for the inner-most outer join | ||
| 8475 | @param cond the predicate to be guarded (must be set) | ||
| 8476 | @param root_idx index of the inner table to stop at | ||
| 8477 | (is NO_PLAN_IDX if this is the WHERE clause) | ||
| 8478 | |||
| 8479 | @return | ||
| 8480 | - pointer to the guarded predicate, if success | ||
| 8481 | - NULL if error | ||
| 8482 | */ | ||
| 8483 | |||
| 8484 | 2690936 | static Item *add_found_match_trig_cond(JOIN *join, plan_idx idx, Item *cond, | |
| 8485 | plan_idx root_idx) { | ||
| 8486 |
3/6✓ Branch 0 taken 2690958 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2690961 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2690963 times.
✗ Branch 5 not taken.
|
2690936 | ASSERT_BEST_REF_IN_JOIN_ORDER(join); |
| 8487 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2690955 times.
|
2690941 | assert(cond->is_bool_func()); |
| 8488 | |||
| 8489 |
2/2✓ Branch 0 taken 4207 times.
✓ Branch 1 taken 2690896 times.
|
2695162 | for (; idx != root_idx; idx = join->best_ref[idx]->first_upper()) { |
| 8490 |
2/4✓ Branch 0 taken 4207 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4207 times.
|
8414 | if (!(cond = new Item_func_trig_cond(cond, nullptr, join, idx, |
| 8491 |
1/2✓ Branch 0 taken 4207 times.
✗ Branch 1 not taken.
|
8414 | Item_func_trig_cond::FOUND_MATCH))) |
| 8492 | ✗ | return nullptr; | |
| 8493 | |||
| 8494 | 4207 | cond->quick_fix_field(); | |
| 8495 | 4207 | cond->update_used_tables(); | |
| 8496 | } | ||
| 8497 | |||
| 8498 | 2690896 | return cond; | |
| 8499 | } | ||
| 8500 | |||
| 8501 | /** | ||
| 8502 | Helper for JOIN::attach_join_conditions(). | ||
| 8503 | Attaches bits of 'join_cond' to each table in the range [first_inner, | ||
| 8504 | last_tab], with proper guards. | ||
| 8505 | If 'sj_mat_cond' is true, we do not see first_inner (and tables on the same | ||
| 8506 | level of it) as inner to anything, as they're at the top from the POV of | ||
| 8507 | the materialization of the tmp table. So, if the SJ-mat nest is A LJ B, | ||
| 8508 | A will get a part of condition without any guard; B will get another part | ||
| 8509 | with a guard on A->found_match. It's like pushing a WHERE. | ||
| 8510 | */ | ||
| 8511 | 530294 | bool JOIN::attach_join_condition_to_nest(plan_idx first_inner, | |
| 8512 | plan_idx last_tab, Item *join_cond, | ||
| 8513 | bool is_sj_mat_cond) { | ||
| 8514 | /* | ||
| 8515 | Add the constant part of the join condition to the first inner table | ||
| 8516 | of the outer join. | ||
| 8517 | */ | ||
| 8518 | Item *cond = | ||
| 8519 | 530294 | make_cond_for_table(thd, join_cond, const_table_map, table_map(0), false); | |
| 8520 |
2/2✓ Branch 0 taken 833 times.
✓ Branch 1 taken 529459 times.
|
530292 | if (cond) { |
| 8521 |
2/2✓ Branch 0 taken 745 times.
✓ Branch 1 taken 88 times.
|
833 | if (!is_sj_mat_cond) { |
| 8522 |
1/2✓ Branch 0 taken 745 times.
✗ Branch 1 not taken.
|
1490 | cond = new Item_func_trig_cond(cond, nullptr, this, first_inner, |
| 8523 |
1/2✓ Branch 0 taken 745 times.
✗ Branch 1 not taken.
|
1490 | Item_func_trig_cond::IS_NOT_NULL_COMPL); |
| 8524 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 745 times.
|
745 | if (!cond) return true; |
| 8525 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 745 times.
|
745 | if (cond->fix_fields(thd, nullptr)) return true; |
| 8526 | } | ||
| 8527 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 745 times.
|
833 | if (best_ref[first_inner]->and_with_condition(cond)) return true; |
| 8528 | } | ||
| 8529 | /* | ||
| 8530 | Split the non-constant part of the join condition into parts that | ||
| 8531 | can be attached to the inner tables of the outer join. | ||
| 8532 | */ | ||
| 8533 |
2/2✓ Branch 0 taken 534397 times.
✓ Branch 1 taken 530267 times.
|
1064664 | for (plan_idx i = first_inner; i <= last_tab; ++i) { |
| 8534 | 534397 | table_map prefix_tables = best_ref[i]->prefix_tables(); | |
| 8535 | 534456 | table_map added_tables = best_ref[i]->added_tables(); | |
| 8536 | |||
| 8537 | /* | ||
| 8538 | When handling the first inner table of an outer join, we may also | ||
| 8539 | reference all tables ahead of this table: | ||
| 8540 | */ | ||
| 8541 |
2/2✓ Branch 0 taken 530274 times.
✓ Branch 1 taken 4199 times.
|
534473 | if (i == first_inner) added_tables = prefix_tables; |
| 8542 | /* | ||
| 8543 | We need RAND_TABLE_BIT on the last inner table, in case there is a | ||
| 8544 | non-deterministic function in the join condition. | ||
| 8545 | (RAND_TABLE_BIT is set for the last table of the join plan, | ||
| 8546 | but this is not sufficient for join conditions, which may have a | ||
| 8547 | last inner table that is ahead of the last table of the join plan). | ||
| 8548 | */ | ||
| 8549 |
2/2✓ Branch 0 taken 530269 times.
✓ Branch 1 taken 4204 times.
|
534473 | if (i == last_tab) { |
| 8550 | 530269 | prefix_tables |= RAND_TABLE_BIT; | |
| 8551 | 530269 | added_tables |= RAND_TABLE_BIT; | |
| 8552 | } | ||
| 8553 | cond = | ||
| 8554 | 534473 | make_cond_for_table(thd, join_cond, prefix_tables, added_tables, false); | |
| 8555 |
2/2✓ Branch 0 taken 2790 times.
✓ Branch 1 taken 531711 times.
|
534501 | if (cond == nullptr) continue; |
| 8556 | /* | ||
| 8557 | If the table is part of an outer join that is embedded in the | ||
| 8558 | outer join currently being processed, wrap the condition in | ||
| 8559 | triggered conditions for match variables of such embedded outer joins. | ||
| 8560 | */ | ||
| 8561 |
3/4✓ Branch 0 taken 44 times.
✓ Branch 1 taken 531667 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 531708 times.
|
1063417 | if (!(cond = add_found_match_trig_cond( |
| 8562 | 531711 | this, best_ref[i]->first_inner(), cond, | |
| 8563 | is_sj_mat_cond ? NO_PLAN_IDX : first_inner))) | ||
| 8564 | ✗ | return true; | |
| 8565 | |||
| 8566 |
2/2✓ Branch 0 taken 531664 times.
✓ Branch 1 taken 44 times.
|
531708 | if (!is_sj_mat_cond) { |
| 8567 | // Add the guard turning the predicate off for the null-complemented row. | ||
| 8568 |
1/2✓ Branch 0 taken 531587 times.
✗ Branch 1 not taken.
|
1063242 | cond = new Item_func_trig_cond(cond, nullptr, this, first_inner, |
| 8569 |
1/2✓ Branch 0 taken 531655 times.
✗ Branch 1 not taken.
|
1063251 | Item_func_trig_cond::IS_NOT_NULL_COMPL); |
| 8570 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 531655 times.
|
531655 | if (!cond) return true; |
| 8571 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 531631 times.
|
531655 | if (cond->fix_fields(thd, nullptr)) return true; |
| 8572 | } | ||
| 8573 | // Add the generated condition to the existing table condition | ||
| 8574 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 531670 times.
|
531675 | if (best_ref[i]->and_with_condition(cond)) return true; |
| 8575 | } | ||
| 8576 | 530267 | return false; | |
| 8577 | } | ||
| 8578 | |||
| 8579 | /** | ||
| 8580 | Attach outer join conditions to generated table conditions in an optimal way. | ||
| 8581 | |||
| 8582 | @param last_tab - Last table that has been added to the current plan. | ||
| 8583 | Pre-condition: If this is the last inner table of an outer | ||
| 8584 | join operation, a join condition is attached to the first | ||
| 8585 | inner table of that outer join operation. | ||
| 8586 | |||
| 8587 | @return false if success, true if error. | ||
| 8588 | |||
| 8589 | Outer join conditions are attached to individual tables, but we can analyze | ||
| 8590 | those conditions only when reaching the last inner table of an outer join | ||
| 8591 | operation. Notice also that a table can be last within several outer join | ||
| 8592 | nests, hence the outer for() loop of this function. | ||
| 8593 | |||
| 8594 | Example: | ||
| 8595 | SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.a=t3.a) ON t1.a=t2.a | ||
| 8596 | |||
| 8597 | Table t3 is last both in the join nest (t2 - t3) and in (t1 - (t2 - t3)) | ||
| 8598 | Thus, join conditions for both join nests will be evaluated when reaching | ||
| 8599 | this table. | ||
| 8600 | |||
| 8601 | For each outer join operation processed, the join condition is split | ||
| 8602 | optimally over the inner tables of the outer join. The split-out conditions | ||
| 8603 | are later referred to as table conditions (but note that several table | ||
| 8604 | conditions stemming from different join operations may be combined into | ||
| 8605 | a composite table condition). | ||
| 8606 | |||
| 8607 | Example: | ||
| 8608 | Consider the above query once more. | ||
| 8609 | The predicate t1.a=t2.a can be evaluated when rows from t1 and t2 are ready, | ||
| 8610 | ie at table t2. The predicate t2.a=t3.a can be evaluated at table t3. | ||
| 8611 | |||
| 8612 | Each non-constant split-out table condition is guarded by a match variable | ||
| 8613 | that enables it only when a matching row is found for all the embedded | ||
| 8614 | outer join operations. | ||
| 8615 | |||
| 8616 | Each split-out table condition is guarded by a variable that turns the | ||
| 8617 | condition off just before a null-complemented row for the outer join | ||
| 8618 | operation is formed. Thus, the join condition will not be checked for | ||
| 8619 | the null-complemented row. | ||
| 8620 | */ | ||
| 8621 | |||
| 8622 | 3779669 | bool JOIN::attach_join_conditions(plan_idx last_tab) { | |
| 8623 |
1/2✓ Branch 0 taken 3779813 times.
✗ Branch 1 not taken.
|
3779669 | DBUG_TRACE; |
| 8624 |
4/6✓ Branch 0 taken 3779822 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3779804 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 3779811 times.
✗ Branch 5 not taken.
|
3779813 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 8625 | |||
| 8626 | 3779802 | JOIN_TAB *lt = best_ref[last_tab]; | |
| 8627 | |||
| 8628 | 3779802 | for (plan_idx first_inner = lt->first_inner(); | |
| 8629 |
6/6✓ Branch 0 taken 533991 times.
✓ Branch 1 taken 3775834 times.
✓ Branch 2 taken 530071 times.
✓ Branch 3 taken 3924 times.
✓ Branch 4 taken 530068 times.
✓ Branch 5 taken 3779761 times.
|
4843820 | first_inner != NO_PLAN_IDX && |
| 8630 | 533991 | best_ref[first_inner]->last_inner() == last_tab; | |
| 8631 | 530048 | first_inner = best_ref[first_inner]->first_upper()) { | |
| 8632 | /* | ||
| 8633 | Table last_tab is the last inner table of an outer join, locate | ||
| 8634 | the corresponding join condition from the first inner table of the | ||
| 8635 | same outer join: | ||
| 8636 | */ | ||
| 8637 | 530068 | Item *const join_cond = best_ref[first_inner]->join_cond(); | |
| 8638 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 530073 times.
|
530073 | assert(join_cond); |
| 8639 |
2/4✓ Branch 0 taken 530048 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 530048 times.
|
530073 | if (attach_join_condition_to_nest(first_inner, last_tab, join_cond, false)) |
| 8640 | ✗ | return true; | |
| 8641 | } | ||
| 8642 |
3/4✓ Branch 0 taken 3779807 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8442 times.
✓ Branch 3 taken 3771375 times.
|
3779761 | if (sj_is_materialize_strategy(lt->get_sj_strategy())) { |
| 8643 | 8442 | plan_idx mat_tbl = NO_PLAN_IDX; | |
| 8644 | /* | ||
| 8645 | The SJ nest's condition contains both the SJ equality condition and the | ||
| 8646 | WHERE of the replaced subquery. This WHERE must be pushed to SJ-inner | ||
| 8647 | tables for evaluation during materialization! | ||
| 8648 | */ | ||
| 8649 | 8442 | Semijoin_mat_exec *sjm = nullptr; | |
| 8650 | 8442 | for (plan_idx j = last_tab;; j--) { | |
| 8651 | 41925 | sjm = best_ref[j]->sj_mat_exec(); | |
| 8652 |
4/4✓ Branch 0 taken 8560 times.
✓ Branch 1 taken 33365 times.
✓ Branch 2 taken 8442 times.
✓ Branch 3 taken 118 times.
|
41925 | if (sjm && sjm->sj_nest == lt->emb_sj_nest) { |
| 8653 | // 'j' is the sj-mat tmp table | ||
| 8654 | 8442 | mat_tbl = j; | |
| 8655 | 8442 | break; | |
| 8656 | } | ||
| 8657 | } | ||
| 8658 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8442 times.
|
8442 | assert(sjm); |
| 8659 |
2/2✓ Branch 0 taken 4583 times.
✓ Branch 1 taken 3859 times.
|
8442 | if (sjm->inner_table_index + sjm->table_count - 1 == (uint)last_tab) { |
| 8660 | // we're at last table of sjmat nest | ||
| 8661 | 4583 | auto join_cond = best_ref[mat_tbl]->join_cond(); | |
| 8662 |
5/8✓ Branch 0 taken 220 times.
✓ Branch 1 taken 4363 times.
✓ Branch 2 taken 220 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 220 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 4583 times.
|
4583 | if (join_cond && attach_join_condition_to_nest(sjm->inner_table_index, |
| 8663 | last_tab, join_cond, true)) | ||
| 8664 | ✗ | return true; | |
| 8665 | } | ||
| 8666 | } | ||
| 8667 | |||
| 8668 | /* | ||
| 8669 | See if 'last_tab' is the first inner of an antijoin nest, | ||
| 8670 | then add a IS NULL condition on it. | ||
| 8671 | By attaching the condition to the first inner table, we know that if | ||
| 8672 | it is not satisfied we can just jump back to the table right before | ||
| 8673 | it. | ||
| 8674 | */ | ||
| 8675 |
4/4✓ Branch 0 taken 571 times.
✓ Branch 1 taken 43192 times.
✓ Branch 2 taken 491 times.
✓ Branch 3 taken 80 times.
|
44334 | if (lt->table_ref->embedding && lt->table_ref->embedding->is_aj_nest() && |
| 8676 |
6/6✓ Branch 0 taken 43763 times.
✓ Branch 1 taken 3736054 times.
✓ Branch 2 taken 346 times.
✓ Branch 3 taken 75 times.
✓ Branch 4 taken 346 times.
✓ Branch 5 taken 3779401 times.
|
3824081 | last_tab == lt->first_inner() && |
| 8677 | /* | ||
| 8678 | Exception: in A AJ (B LJ C) where C is a single table: there is no | ||
| 8679 | join nest for C as it's single; C->embedding is thus the AJ nest; but | ||
| 8680 | C->first_inner() is C (as it's the first inner of the LJ operation). | ||
| 8681 | In that case it's not the first inner table of the AJ. | ||
| 8682 | Catch this case: | ||
| 8683 | */ | ||
| 8684 | 491 | !lt->table_ref->join_cond()) { | |
| 8685 |
1/2✓ Branch 0 taken 346 times.
✗ Branch 1 not taken.
|
692 | Item *cond = new Item_func_false(); |
| 8686 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 346 times.
|
346 | if (!cond) return true; |
| 8687 | // This is a signal for JOIN::create_access_paths | ||
| 8688 | 346 | cond->item_name.set(antijoin_null_cond); | |
| 8689 | /* | ||
| 8690 | For A AJ B ON COND, we need an IS NULL condition which | ||
| 8691 | is tested on the result rows of A LEFT JOIN B ON COND. | ||
| 8692 | It must be tested only after the "match status" of a row of B has been | ||
| 8693 | decided, so is wrapped in a condition triggered by B->found_match. | ||
| 8694 | To have it test IS NULL, it's wrapped in a triggered condition which is | ||
| 8695 | false if B is not NULL-complemented. | ||
| 8696 | We needn't wrap this condition with triggers from upper nests, hence the | ||
| 8697 | last argument of the call below. | ||
| 8698 | */ | ||
| 8699 |
1/2✓ Branch 0 taken 346 times.
✗ Branch 1 not taken.
|
346 | cond = add_found_match_trig_cond(this, last_tab, cond, lt->first_upper()); |
| 8700 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 346 times.
|
346 | if (!cond) return true; |
| 8701 |
1/2✓ Branch 0 taken 346 times.
✗ Branch 1 not taken.
|
692 | cond = new Item_func_trig_cond(cond, nullptr, this, last_tab, |
| 8702 |
1/2✓ Branch 0 taken 346 times.
✗ Branch 1 not taken.
|
692 | Item_func_trig_cond::IS_NOT_NULL_COMPL); |
| 8703 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 346 times.
|
346 | if (!cond) return true; |
| 8704 |
2/4✓ Branch 0 taken 346 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 346 times.
|
346 | if (cond->fix_fields(thd, nullptr)) return true; |
| 8705 |
2/4✓ Branch 0 taken 346 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 346 times.
|
346 | if (lt->and_with_condition(cond)) return true; |
| 8706 | 346 | lt->table()->reginfo.not_exists_optimize = true; | |
| 8707 | |||
| 8708 | // The relevant secondary engines don't support antijoin, so don't enable | ||
| 8709 | // this optimization for them. | ||
| 8710 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 322 times.
|
346 | assert(thd->secondary_engine_optimization() != |
| 8711 | Secondary_engine_optimization::SECONDARY); | ||
| 8712 | } | ||
| 8713 | |||
| 8714 | 3779723 | return false; | |
| 8715 | 3779723 | } | |
| 8716 | |||
| 8717 | /***************************************************************************** | ||
| 8718 | Remove calculation with tables that aren't yet read. Remove also tests | ||
| 8719 | against fields that are read through key where the table is not a | ||
| 8720 | outer join table. | ||
| 8721 | We can't remove tests that are made against columns which are stored | ||
| 8722 | in sorted order. | ||
| 8723 | *****************************************************************************/ | ||
| 8724 | |||
| 8725 | 3137681 | static Item *part_of_refkey(TABLE *table, TABLE_REF *ref, const Field *field) { | |
| 8726 | 3137681 | uint ref_parts = ref->key_parts; | |
| 8727 |
2/2✓ Branch 0 taken 2466732 times.
✓ Branch 1 taken 670949 times.
|
3137681 | if (ref_parts) { |
| 8728 |
2/2✓ Branch 0 taken 568 times.
✓ Branch 1 taken 2466146 times.
|
2466732 | if (ref->has_guarded_conds()) return nullptr; |
| 8729 | |||
| 8730 | 2466146 | const KEY_PART_INFO *key_part = table->key_info[ref->key].key_part; | |
| 8731 | |||
| 8732 |
2/2✓ Branch 0 taken 2910553 times.
✓ Branch 1 taken 102785 times.
|
3013338 | for (uint part = 0; part < ref_parts; part++, key_part++) |
| 8733 |
4/4✓ Branch 0 taken 2363845 times.
✓ Branch 1 taken 546688 times.
✓ Branch 2 taken 2363341 times.
✓ Branch 3 taken 547192 times.
|
5274398 | if (field->eq(key_part->field) && |
| 8734 |
2/2✓ Branch 0 taken 2363337 times.
✓ Branch 1 taken 508 times.
|
2363845 | !(key_part->key_part_flag & HA_PART_KEY_SEG)) |
| 8735 | 2363341 | return ref->items[part]; | |
| 8736 | } | ||
| 8737 | 773734 | return nullptr; | |
| 8738 | } | ||
| 8739 | |||
| 8740 | 2352940 | bool ref_lookup_subsumes_comparison(Field *field, Item *right_item) { | |
| 8741 | 2352940 | right_item = right_item->real_item(); | |
| 8742 |
2/2✓ Branch 0 taken 1846022 times.
✓ Branch 1 taken 506987 times.
|
2353002 | if (right_item->type() == Item::FIELD_ITEM) |
| 8743 | 1846022 | return (field->eq_def(down_cast<Item_field *>(right_item)->field)); | |
| 8744 | /* remove equalities injected by IN->EXISTS transformation */ | ||
| 8745 |
2/2✓ Branch 0 taken 1231 times.
✓ Branch 1 taken 505740 times.
|
506987 | else if (right_item->type() == Item::CACHE_ITEM) |
| 8746 | 1231 | return down_cast<Item_cache *>(right_item)->eq_def(field); | |
| 8747 |
6/6✓ Branch 0 taken 505546 times.
✓ Branch 1 taken 199 times.
✓ Branch 2 taken 505527 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 505527 times.
✓ Branch 5 taken 215 times.
|
505740 | if (right_item->const_for_execution() && !right_item->is_null()) { |
| 8748 | /* | ||
| 8749 | We can remove all fields except: | ||
| 8750 | 1. String data types: | ||
| 8751 | - For BINARY/VARBINARY fields with equality against a | ||
| 8752 | string: Ref access can return more rows than match the | ||
| 8753 | string. The reason seems to be that the string constant | ||
| 8754 | is not "padded" to the full length of the field when | ||
| 8755 | setting up ref access. @todo Change how ref access for | ||
| 8756 | BINARY/VARBINARY fields are done so that only qualifying | ||
| 8757 | rows are returned from the storage engine. | ||
| 8758 | 2. Float data type: Comparison of float can differ | ||
| 8759 | - When we search "WHERE field=value" using an index, | ||
| 8760 | the "value" side is converted from double to float by | ||
| 8761 | Field_float::store(), then two floats are compared. | ||
| 8762 | - When we search "WHERE field=value" without indexes, | ||
| 8763 | the "field" side is converted from float to double by | ||
| 8764 | Field_float::val_real(), then two doubles are compared. | ||
| 8765 | */ | ||
| 8766 |
4/4✓ Branch 0 taken 25918 times.
✓ Branch 1 taken 479607 times.
✓ Branch 2 taken 693 times.
✓ Branch 3 taken 504831 times.
|
531444 | if (field->type() == MYSQL_TYPE_STRING && |
| 8767 |
2/2✓ Branch 0 taken 693 times.
✓ Branch 1 taken 25224 times.
|
25918 | field->charset()->pad_attribute == NO_PAD) { |
| 8768 | /* | ||
| 8769 | For "NO PAD" collations on CHAR columns, this function must return | ||
| 8770 | false, because removal of trailing space in CHAR columns makes the | ||
| 8771 | table value and the index value compare differently. As the column | ||
| 8772 | strips trailing spaces, it can return false candidates. Further | ||
| 8773 | comparison of the actual table values is required. | ||
| 8774 | */ | ||
| 8775 | 693 | return false; | |
| 8776 | } | ||
| 8777 | 504831 | if (!((field->type() == MYSQL_TYPE_STRING || // 1 | |
| 8778 |
2/2✓ Branch 0 taken 457584 times.
✓ Branch 1 taken 22022 times.
|
479603 | field->type() == MYSQL_TYPE_VARCHAR) && |
| 8779 |
6/6✓ Branch 0 taken 479603 times.
✓ Branch 1 taken 25225 times.
✓ Branch 2 taken 482715 times.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 504815 times.
✓ Branch 5 taken 7 times.
|
1467214 | field->binary()) && |
| 8780 |
3/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 504796 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
|
504737 | !(field->type() == MYSQL_TYPE_FLOAT && field->decimals() > 0)) // 2 |
| 8781 | { | ||
| 8782 | 504815 | return !right_item->save_in_field_no_warnings(field, true); | |
| 8783 | } | ||
| 8784 | } | ||
| 8785 | 222 | return false; | |
| 8786 | } | ||
| 8787 | |||
| 8788 | /** | ||
| 8789 | @brief | ||
| 8790 | Identify redundant predicates. | ||
| 8791 | |||
| 8792 | @details | ||
| 8793 | Test if the equality predicate 'left_item = right_item' is redundant | ||
| 8794 | due to a REF-access already being set up on the table, where 'left_item' is | ||
| 8795 | part of the REF-key being used, and 'right_item' is equal to the key value | ||
| 8796 | specified for that field in the key. | ||
| 8797 | In such cases the predicate is known to be 'true' for any rows retrieved | ||
| 8798 | from that table. Thus it is redundant. | ||
| 8799 | |||
| 8800 | @param left_item The Item_field possibly being part of A ref-KEY. | ||
| 8801 | @param right_item The equality value specified for 'left_item'. | ||
| 8802 | |||
| 8803 | @return 'true' if the predicate is redundant. | ||
| 8804 | |||
| 8805 | @note See comments in reduce_cond_for_table() about careful | ||
| 8806 | usage/modifications of test_if_ref(). | ||
| 8807 | */ | ||
| 8808 | |||
| 8809 | 3141711 | static bool test_if_ref(Item_field *left_item, Item *right_item) { | |
| 8810 |
2/2✓ Branch 0 taken 2638 times.
✓ Branch 1 taken 3139073 times.
|
3141711 | if (left_item->depended_from) |
| 8811 | 2638 | return false; // don't even read join_tab of inner subquery! | |
| 8812 | 3139073 | Field *field = left_item->field; | |
| 8813 | 3139073 | JOIN_TAB *join_tab = field->table->reginfo.join_tab; | |
| 8814 |
2/2✓ Branch 0 taken 130 times.
✓ Branch 1 taken 3138943 times.
|
3139073 | if (join_tab == nullptr) return false; |
| 8815 | |||
| 8816 |
4/6✓ Branch 0 taken 3139067 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3139062 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 3139042 times.
✗ Branch 5 not taken.
|
3138943 | ASSERT_BEST_REF_IN_JOIN_ORDER(join_tab->join()); |
| 8817 | |||
| 8818 | // No need to change const test | ||
| 8819 |
6/6✓ Branch 0 taken 3138615 times.
✓ Branch 1 taken 421 times.
✓ Branch 2 taken 3137718 times.
✓ Branch 3 taken 903 times.
✓ Branch 4 taken 3137719 times.
✓ Branch 5 taken 1323 times.
|
6277657 | if (!field->table->const_table && |
| 8820 | /* "ref_or_null" implements "x=y or x is null", not "x=y" */ | ||
| 8821 | 3138615 | (join_tab->type() != JT_REF_OR_NULL)) { | |
| 8822 | 3137719 | Item *ref_item = part_of_refkey(field->table, &join_tab->ref(), field); | |
| 8823 |
4/4✓ Branch 0 taken 2363350 times.
✓ Branch 1 taken 774374 times.
✓ Branch 2 taken 2352817 times.
✓ Branch 3 taken 10369 times.
|
5490719 | return (ref_item && ref_item->eq(right_item, true) && |
| 8824 |
2/2✓ Branch 0 taken 2345846 times.
✓ Branch 1 taken 7149 times.
|
5490555 | ref_lookup_subsumes_comparison(field, right_item)); |
| 8825 | } | ||
| 8826 | 1323 | return false; // keep predicate | |
| 8827 | } | ||
| 8828 | |||
| 8829 | /** | ||
| 8830 | @brief | ||
| 8831 | Remove redundant predicates from condition, return the reduced condition. | ||
| 8832 | |||
| 8833 | @details | ||
| 8834 | A predicate of the form 'field = value' may be redundant if the | ||
| 8835 | (ref-) access chosen for the table use an index containing 'field', | ||
| 8836 | where 'value' is specified as (part of) its ref-key. This method remove | ||
| 8837 | such redundant predicates, thus reducing the condition, possibly | ||
| 8838 | eliminating it entirely. | ||
| 8839 | |||
| 8840 | If comparing 'values' against outer-joined tables, these are possibly | ||
| 8841 | 'null-extended'. Thus the usage of these values in the ref-key, is not | ||
| 8842 | sufficient anymore to guarantee that 'field = value' is 'TRUE'. | ||
| 8843 | The 'null_extended' argument hold the table_map of any such possibly | ||
| 8844 | null-extended tables which are excluded from the above 'reduce' logic. | ||
| 8845 | |||
| 8846 | Any tables referred in Item_func_trig_cond(FOUND_MATCH) conditions are | ||
| 8847 | aggregated into this null_extended table_map. | ||
| 8848 | |||
| 8849 | @param cond The condition to be 'reduced'. | ||
| 8850 | @param null_extended table_map of possibly null-extended outer-tables. | ||
| 8851 | |||
| 8852 | @return The condition with redundant predicates removed, | ||
| 8853 | possibly nullptr. | ||
| 8854 | */ | ||
| 8855 | 6398066 | static Item *reduce_cond_for_table(Item *cond, table_map null_extended) { | |
| 8856 |
1/2✓ Branch 0 taken 6398253 times.
✗ Branch 1 not taken.
|
6398066 | DBUG_TRACE; |
| 8857 |
5/8✓ Branch 0 taken 6398248 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 6398241 times.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
|
6398253 | DBUG_EXECUTE("where", |
| 8858 | print_where(current_thd, cond, "cond term", QT_ORDINARY);); | ||
| 8859 | |||
| 8860 |
3/4✓ Branch 0 taken 6398220 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1190761 times.
✓ Branch 3 taken 5207459 times.
|
6398248 | if (cond->type() == Item::COND_ITEM) { |
| 8861 | 1190761 | List<Item> *arguments = down_cast<Item_cond *>(cond)->argument_list(); | |
| 8862 |
1/2✓ Branch 0 taken 1190766 times.
✗ Branch 1 not taken.
|
1190768 | List_iterator<Item> li(*arguments); |
| 8863 |
3/4✓ Branch 0 taken 1190726 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1165000 times.
✓ Branch 3 taken 25726 times.
|
1190766 | if (down_cast<Item_cond *>(cond)->functype() == Item_func::COND_AND_FUNC) { |
| 8864 | Item *item; | ||
| 8865 |
2/2✓ Branch 0 taken 3102769 times.
✓ Branch 1 taken 1165029 times.
|
4267787 | while ((item = li++)) { |
| 8866 |
1/2✓ Branch 0 taken 3102806 times.
✗ Branch 1 not taken.
|
3102769 | Item *upd_item = reduce_cond_for_table(item, null_extended); |
| 8867 |
2/2✓ Branch 0 taken 1224090 times.
✓ Branch 1 taken 1878716 times.
|
3102806 | if (upd_item == nullptr) { |
| 8868 |
1/2✓ Branch 0 taken 1224071 times.
✗ Branch 1 not taken.
|
1224090 | li.remove(); |
| 8869 |
2/2✓ Branch 0 taken 1869 times.
✓ Branch 1 taken 1876847 times.
|
1878716 | } else if (upd_item != item) { |
| 8870 | 1869 | li.replace(upd_item); | |
| 8871 | } | ||
| 8872 | } | ||
| 8873 |
3/3✓ Branch 0 taken 308517 times.
✓ Branch 1 taken 131985 times.
✓ Branch 2 taken 724527 times.
|
1165029 | switch (arguments->elements) { |
| 8874 | 308517 | case 0: | |
| 8875 | 440537 | return nullptr; // All 'true' -> And-cond true | |
| 8876 | 131985 | case 1: | |
| 8877 | 131985 | return arguments->head(); | |
| 8878 | } | ||
| 8879 | } else { // Or list | ||
| 8880 | Item *item; | ||
| 8881 |
2/2✓ Branch 0 taken 67364 times.
✓ Branch 1 taken 25707 times.
|
93071 | while ((item = li++)) { |
| 8882 |
1/2✓ Branch 0 taken 67378 times.
✗ Branch 1 not taken.
|
67364 | Item *upd_item = reduce_cond_for_table(item, null_extended); |
| 8883 |
2/2✓ Branch 0 taken 33 times.
✓ Branch 1 taken 67345 times.
|
67378 | if (upd_item == nullptr) { |
| 8884 | 33 | return nullptr; // Term 'true' -> entire Or-cond true | |
| 8885 |
2/2✓ Branch 0 taken 52 times.
✓ Branch 1 taken 67293 times.
|
67345 | } else if (upd_item != item) { |
| 8886 | 52 | li.replace(upd_item); | |
| 8887 | } | ||
| 8888 | } | ||
| 8889 | } | ||
| 8890 |
3/4✓ Branch 0 taken 5207397 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5206888 times.
✓ Branch 3 taken 509 times.
|
5207459 | } else if (cond->type() == Item::FUNC_ITEM) { |
| 8891 | 5206888 | Item_func *func = down_cast<Item_func *>(cond); | |
| 8892 |
3/4✓ Branch 0 taken 5206812 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 540231 times.
✓ Branch 3 taken 4666581 times.
|
5206999 | if (func->functype() == Item_func::TRIG_COND_FUNC) { |
| 8893 | 540231 | Item_func_trig_cond *func_trig = down_cast<Item_func_trig_cond *>(func); | |
| 8894 |
2/2✓ Branch 0 taken 4207 times.
✓ Branch 1 taken 536002 times.
|
540222 | if (func_trig->get_trig_type() == Item_func_trig_cond::FOUND_MATCH) { |
| 8895 | /* | ||
| 8896 | All inner-tables are possible null-extended when evaluating | ||
| 8897 | the 'FOUND_MATCH'. Thus, predicates embedded in this trig_cond, | ||
| 8898 | referring these tables, should not be eliminated. | ||
| 8899 | -> Add to null_extended map. | ||
| 8900 | */ | ||
| 8901 |
1/2✓ Branch 0 taken 4207 times.
✗ Branch 1 not taken.
|
4207 | null_extended |= func_trig->get_inner_tables(); |
| 8902 | } | ||
| 8903 | |||
| 8904 |
1/2✓ Branch 0 taken 540294 times.
✗ Branch 1 not taken.
|
540209 | Item *cond_arg = func->arguments()[0]; |
| 8905 |
1/2✓ Branch 0 taken 540326 times.
✗ Branch 1 not taken.
|
540294 | Item *upd_arg = reduce_cond_for_table(cond_arg, null_extended); |
| 8906 |
2/2✓ Branch 0 taken 514957 times.
✓ Branch 1 taken 25369 times.
|
540326 | if (upd_arg == nullptr) { |
| 8907 | 514957 | return nullptr; | |
| 8908 | } | ||
| 8909 |
1/2✓ Branch 0 taken 25371 times.
✗ Branch 1 not taken.
|
25369 | func->arguments()[0] = upd_arg; |
| 8910 | } | ||
| 8911 | |||
| 8912 |
3/4✓ Branch 0 taken 4666596 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2993717 times.
✓ Branch 3 taken 1672879 times.
|
4666581 | else if (func->functype() == Item_func::EQ_FUNC) { |
| 8913 | /* | ||
| 8914 | Remove equalities that are guaranteed to be true by use of 'ref' access | ||
| 8915 | method. | ||
| 8916 | Note that ref access implements "table1.field1 <=> | ||
| 8917 | table2.indexed_field2", i.e. if it passed a NULL field1, it will return | ||
| 8918 | NULL indexed_field2 if there are. | ||
| 8919 | Thus the equality "table1.field1 = table2.indexed_field2", | ||
| 8920 | is equivalent to "ref access AND table1.field1 IS NOT NULL" | ||
| 8921 | i.e. "ref access and proper setting/testing of ref->null_rejecting". | ||
| 8922 | Thus, we must be careful, that when we remove equalities below we also | ||
| 8923 | set ref->null_rejecting, and test it at execution; otherwise wrong NULL | ||
| 8924 | matches appear. | ||
| 8925 | So: | ||
| 8926 | - for the optimization phase, the code which is below, and the code in | ||
| 8927 | test_if_ref(), and in add_key_field(), must be kept in sync: if the | ||
| 8928 | applicability conditions in one place are relaxed, they should also be | ||
| 8929 | relaxed elsewhere. | ||
| 8930 | - for the execution phase, all possible execution methods must test | ||
| 8931 | ref->null_rejecting. | ||
| 8932 | */ | ||
| 8933 |
2/4✓ Branch 0 taken 2993769 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2993752 times.
✗ Branch 3 not taken.
|
2993717 | Item *left_item = func->arguments()[0]->real_item(); |
| 8934 |
2/4✓ Branch 0 taken 2993791 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2993788 times.
✗ Branch 3 not taken.
|
2993752 | Item *right_item = func->arguments()[1]->real_item(); |
| 8935 |
1/2✓ Branch 0 taken 2993779 times.
✗ Branch 1 not taken.
|
2993788 | if ((left_item->type() == Item::FIELD_ITEM && |
| 8936 |
3/4✓ Branch 0 taken 2967176 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2966676 times.
✓ Branch 3 taken 500 times.
|
2967176 | !(left_item->used_tables() & null_extended) && |
| 8937 |
7/8✓ Branch 0 taken 2967176 times.
✓ Branch 1 taken 26603 times.
✓ Branch 2 taken 2966691 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 622521 times.
✓ Branch 5 taken 2344170 times.
✓ Branch 6 taken 2345827 times.
✓ Branch 7 taken 647963 times.
|
6610075 | test_if_ref(down_cast<Item_field *>(left_item), right_item)) || |
| 8938 |
3/4✓ Branch 0 taken 649620 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 176336 times.
✓ Branch 3 taken 473284 times.
|
649624 | (right_item->type() == Item::FIELD_ITEM && |
| 8939 |
3/4✓ Branch 0 taken 176336 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 175141 times.
✓ Branch 3 taken 1195 times.
|
176336 | !(right_item->used_tables() & null_extended) && |
| 8940 |
3/4✓ Branch 0 taken 175141 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1660 times.
✓ Branch 3 taken 173481 times.
|
175141 | test_if_ref(down_cast<Item_field *>(right_item), left_item))) { |
| 8941 | 2345827 | return nullptr; | |
| 8942 | } | ||
| 8943 | } | ||
| 8944 | } | ||
| 8945 | 3096956 | return cond; | |
| 8946 | 6398277 | } | |
| 8947 | |||
| 8948 | /** | ||
| 8949 | @brief | ||
| 8950 | Remove redundant predicates and cache constant expressions. | ||
| 8951 | |||
| 8952 | @details | ||
| 8953 | Do a final round on pushed down table conditions and HAVING | ||
| 8954 | clause. Optimize them for faster execution by removing | ||
| 8955 | predicates being obsolete due to the access path selected | ||
| 8956 | for the table. Constant expressions are also cached | ||
| 8957 | to avoid evaluating them for each row being compared. | ||
| 8958 | |||
| 8959 | @return False if success, True if error | ||
| 8960 | |||
| 8961 | @note This function is run after conditions have been pushed down to | ||
| 8962 | individual tables, so transformation is applied to JOIN_TAB::condition | ||
| 8963 | and not to the WHERE condition. | ||
| 8964 | */ | ||
| 8965 | 1732077 | bool JOIN::finalize_table_conditions() { | |
| 8966 | /* | ||
| 8967 | Unnecessary to reduce conditions for const tables as they are only | ||
| 8968 | evaluated once. | ||
| 8969 | */ | ||
| 8970 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1732188 times.
|
1732077 | assert(!plan_is_const()); |
| 8971 |
4/6✓ Branch 0 taken 1732176 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 1732176 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1732176 times.
✗ Branch 5 not taken.
|
1732188 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 8972 | |||
| 8973 | 1732188 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 8974 |
1/2✓ Branch 0 taken 1732193 times.
✗ Branch 1 not taken.
|
1732188 | Opt_trace_object trace_wrapper(trace); |
| 8975 |
1/2✓ Branch 0 taken 1732194 times.
✗ Branch 1 not taken.
|
1732193 | Opt_trace_array trace_tables(trace, "finalizing_table_conditions"); |
| 8976 | |||
| 8977 |
2/2✓ Branch 0 taken 6079491 times.
✓ Branch 1 taken 1732349 times.
|
7811840 | for (uint i = const_tables; i < tables; i++) { |
| 8978 | 6079491 | Item *condition = best_ref[i]->condition(); | |
| 8979 |
2/2✓ Branch 0 taken 3391908 times.
✓ Branch 1 taken 2687668 times.
|
6079576 | if (condition == nullptr) continue; |
| 8980 | |||
| 8981 | /* | ||
| 8982 | Table predicates known to be true by the selected | ||
| 8983 | (ref-)access method may be removed from the condition | ||
| 8984 | */ | ||
| 8985 |
1/2✓ Branch 0 taken 2687762 times.
✗ Branch 1 not taken.
|
2687668 | Opt_trace_object trace_cond(trace); |
| 8986 |
1/2✓ Branch 0 taken 2687763 times.
✗ Branch 1 not taken.
|
2687762 | trace_cond.add_utf8_table(best_ref[i]->table_ref); |
| 8987 |
1/2✓ Branch 0 taken 2687759 times.
✗ Branch 1 not taken.
|
2687763 | trace_cond.add("original_table_condition", condition); |
| 8988 | |||
| 8989 | /* | ||
| 8990 | Calculate the set of possibly NULL extended tables when 'condition' | ||
| 8991 | is evaluated. As it is evaluated on a found row from table, that | ||
| 8992 | table is subtracted from the nullable tables. Note that a FOUND_MATCH | ||
| 8993 | trigger is a special case, handled in reduce_cond_for_table(). | ||
| 8994 | */ | ||
| 8995 | const table_map null_extended = | ||
| 8996 | 2687759 | query_block->outer_join & ~best_ref[i]->table_ref->map(); | |
| 8997 |
1/2✓ Branch 0 taken 2687791 times.
✗ Branch 1 not taken.
|
2687775 | condition = reduce_cond_for_table(condition, null_extended); |
| 8998 |
3/4✓ Branch 0 taken 1257525 times.
✓ Branch 1 taken 1430266 times.
✓ Branch 2 taken 1257524 times.
✗ Branch 3 not taken.
|
2687791 | if (condition != nullptr) condition->update_used_tables(); |
| 8999 | |||
| 9000 | /* | ||
| 9001 | Cache constant expressions in table conditions. | ||
| 9002 | (Moved down from WHERE- and ON-clauses) | ||
| 9003 | */ | ||
| 9004 |
2/2✓ Branch 0 taken 1257524 times.
✓ Branch 1 taken 1430266 times.
|
2687790 | if (condition != nullptr) { |
| 9005 |
1/2✓ Branch 0 taken 1257483 times.
✗ Branch 1 not taken.
|
1257524 | cache_const_expr_arg cache_arg; |
| 9006 | 1257483 | cache_const_expr_arg *analyzer_arg = &cache_arg; | |
| 9007 |
1/2✓ Branch 0 taken 1257527 times.
✗ Branch 1 not taken.
|
1257483 | condition = condition->compile( |
| 9008 | &Item::cache_const_expr_analyzer, (uchar **)&analyzer_arg, | ||
| 9009 | &Item::cache_const_expr_transformer, (uchar *)&cache_arg); | ||
| 9010 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1257526 times.
|
1257527 | if (condition == nullptr) return true; |
| 9011 | } | ||
| 9012 | |||
| 9013 |
1/2✓ Branch 0 taken 2687738 times.
✗ Branch 1 not taken.
|
2687792 | trace_cond.add("final_table_condition ", condition); |
| 9014 | 2687738 | best_ref[i]->set_condition(condition); | |
| 9015 |
1/2✓ Branch 0 taken 2687738 times.
✗ Branch 1 not taken.
|
2687780 | } |
| 9016 | |||
| 9017 | /* Cache constant expressions in HAVING-clauses. */ | ||
| 9018 |
2/2✓ Branch 0 taken 8524 times.
✓ Branch 1 taken 1723825 times.
|
1732349 | if (having_cond != nullptr) { |
| 9019 |
1/2✓ Branch 0 taken 8524 times.
✗ Branch 1 not taken.
|
8524 | cache_const_expr_arg cache_arg; |
| 9020 | 8524 | cache_const_expr_arg *analyzer_arg = &cache_arg; | |
| 9021 |
1/2✓ Branch 0 taken 8524 times.
✗ Branch 1 not taken.
|
8524 | having_cond = having_cond->compile( |
| 9022 | &Item::cache_const_expr_analyzer, (uchar **)&analyzer_arg, | ||
| 9023 | &Item::cache_const_expr_transformer, (uchar *)&cache_arg); | ||
| 9024 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8524 times.
|
8524 | if (having_cond == nullptr) return true; |
| 9025 | } | ||
| 9026 | 1732349 | return false; | |
| 9027 | 1732348 | } | |
| 9028 | |||
| 9029 | /** | ||
| 9030 | @brief | ||
| 9031 | Add keys to derived tables'/views' result tables in a list | ||
| 9032 | |||
| 9033 | @details | ||
| 9034 | This function generates keys for all derived tables/views of the query_block | ||
| 9035 | to which this join corresponds to with help of the TABLE_LIST:generate_keys | ||
| 9036 | function. | ||
| 9037 | |||
| 9038 | @return false all keys were successfully added. | ||
| 9039 | @return true OOM error | ||
| 9040 | */ | ||
| 9041 | |||
| 9042 | 2413 | bool JOIN::generate_derived_keys() { | |
| 9043 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2413 times.
|
2413 | assert(query_block->materialized_derived_table_count); |
| 9044 | |||
| 9045 |
2/2✓ Branch 0 taken 5581 times.
✓ Branch 1 taken 2413 times.
|
7994 | for (TABLE_LIST *table = query_block->leaf_tables; table; |
| 9046 | 5581 | table = table->next_leaf) { | |
| 9047 | 5581 | table->derived_keys_ready = true; | |
| 9048 | /* Process tables that aren't materialized yet. */ | ||
| 9049 |
5/6✓ Branch 0 taken 2769 times.
✓ Branch 1 taken 2812 times.
✓ Branch 2 taken 2177 times.
✓ Branch 3 taken 592 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5581 times.
|
7758 | if (table->uses_materialization() && !table->table->is_created() && |
| 9050 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2177 times.
|
2177 | table->generate_keys()) |
| 9051 | ✗ | return true; | |
| 9052 | } | ||
| 9053 | 2413 | return false; | |
| 9054 | } | ||
| 9055 | |||
| 9056 | /** | ||
| 9057 | For each materialized derived table/view, informs every TABLE of the key it | ||
| 9058 | will (not) use, segregates used keys from unused keys in TABLE::key_info, | ||
| 9059 | and eliminates unused keys. | ||
| 9060 | */ | ||
| 9061 | |||
| 9062 | 177564 | void JOIN::finalize_derived_keys() { | |
| 9063 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 177564 times.
|
177564 | assert(query_block->materialized_derived_table_count); |
| 9064 |
3/6✓ Branch 0 taken 177564 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 177564 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 177564 times.
✗ Branch 5 not taken.
|
177564 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 9065 | |||
| 9066 | 177564 | bool adjust_key_count = false; | |
| 9067 | 177564 | table_map processed_tables = 0; | |
| 9068 | |||
| 9069 |
2/2✓ Branch 0 taken 359737 times.
✓ Branch 1 taken 177564 times.
|
537301 | for (uint i = 0; i < tables; i++) { |
| 9070 | 359737 | JOIN_TAB *tab = best_ref[i]; | |
| 9071 | 359737 | TABLE *table = tab->table(); | |
| 9072 | 359737 | TABLE_LIST *table_ref = tab->table_ref; | |
| 9073 | /* | ||
| 9074 | Save chosen key description if: | ||
| 9075 | 1) it's a materialized derived table | ||
| 9076 | 2) it's not yet instantiated | ||
| 9077 | 3) some keys are defined for it | ||
| 9078 | */ | ||
| 9079 |
2/2✓ Branch 0 taken 178114 times.
✓ Branch 1 taken 3207 times.
|
181321 | if (table && table_ref->uses_materialization() && // (1) |
| 9080 |
6/6✓ Branch 0 taken 181321 times.
✓ Branch 1 taken 178416 times.
✓ Branch 2 taken 175723 times.
✓ Branch 3 taken 2391 times.
✓ Branch 4 taken 2024 times.
✓ Branch 5 taken 357713 times.
|
716781 | !table->is_created() && // (2) |
| 9081 |
2/2✓ Branch 0 taken 2024 times.
✓ Branch 1 taken 173699 times.
|
175723 | table->s->keys > 0) // (3) |
| 9082 | { | ||
| 9083 | /* | ||
| 9084 | If there are two local references to the same CTE, and they use | ||
| 9085 | the same key, the iteration for the second reference is unnecessary. | ||
| 9086 | */ | ||
| 9087 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 2013 times.
|
3063 | if (processed_tables & table_ref->map()) continue; |
| 9088 | |||
| 9089 | 2013 | adjust_key_count = true; | |
| 9090 | |||
| 9091 |
1/2✓ Branch 0 taken 2013 times.
✗ Branch 1 not taken.
|
2013 | Key_map used_keys; |
| 9092 | |||
| 9093 | // Mark all unique indexes as in use, since they have an effect | ||
| 9094 | // (deduplication) whether any expression refers to them or not. | ||
| 9095 | // In particular, they are used if we want to materialize a UNION DISTINCT | ||
| 9096 | // directly into the derived table. | ||
| 9097 |
2/2✓ Branch 0 taken 11871 times.
✓ Branch 1 taken 2013 times.
|
13884 | for (uint key_idx = 0; key_idx < table->s->keys; ++key_idx) { |
| 9098 |
2/2✓ Branch 0 taken 411 times.
✓ Branch 1 taken 11460 times.
|
11871 | if (table->key_info[key_idx].flags & HA_NOSAME) { |
| 9099 | 411 | used_keys.set_bit(key_idx); | |
| 9100 | } | ||
| 9101 | } | ||
| 9102 | |||
| 9103 | // Same for the hash key used for manual deduplication, if any. (It always | ||
| 9104 | // has index 0 if it exists.) | ||
| 9105 |
2/2✓ Branch 0 taken 187 times.
✓ Branch 1 taken 1826 times.
|
2013 | if (table->hash_field) { |
| 9106 | 187 | used_keys.set_bit(0); | |
| 9107 | } | ||
| 9108 | |||
| 9109 | 2013 | Key_use *const keyuse = tab->position()->key; | |
| 9110 |
6/6✓ Branch 0 taken 1039 times.
✓ Branch 1 taken 974 times.
✓ Branch 2 taken 509 times.
✓ Branch 3 taken 530 times.
✓ Branch 4 taken 509 times.
✓ Branch 5 taken 1504 times.
|
2013 | if (keyuse == nullptr && used_keys.is_clear_all()) { |
| 9111 | // Nothing uses any keys. | ||
| 9112 | 509 | tab->keys().clear_all(); | |
| 9113 | 509 | tab->const_keys.clear_all(); | |
| 9114 | 509 | continue; | |
| 9115 | } | ||
| 9116 | |||
| 9117 | 1504 | Derived_refs_iterator it(table_ref); | |
| 9118 |
3/4✓ Branch 0 taken 16051 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14547 times.
✓ Branch 3 taken 1504 times.
|
16051 | while (TABLE *t = it.get_next()) { |
| 9119 | /* | ||
| 9120 | Eliminate possible keys created by this JOIN and which it | ||
| 9121 | doesn't use. | ||
| 9122 | Collect all keys of this table which are used by any reference in | ||
| 9123 | this query block. Any other query block doesn't matter as: | ||
| 9124 | - either it was optimized before, so it's not using a key we may | ||
| 9125 | want to drop. | ||
| 9126 | - or it was optimized in this same window, so: | ||
| 9127 | * either we own the window, then any key we may want to | ||
| 9128 | drop is not visible to it. | ||
| 9129 | * or it owns the window, then we are using only existing | ||
| 9130 | keys. | ||
| 9131 | - or it will be optimized after, so it's not using any key yet. | ||
| 9132 | |||
| 9133 | used_keys is a mix of possible used keys and existing used keys. | ||
| 9134 | */ | ||
| 9135 |
2/2✓ Branch 0 taken 1551 times.
✓ Branch 1 taken 12996 times.
|
14547 | if (t->pos_in_table_list->query_block == query_block) { |
| 9136 | 1551 | JOIN_TAB *jtab = t->reginfo.join_tab; | |
| 9137 | 1551 | Key_use *keyuse_1 = jtab->position()->key; | |
| 9138 |
2/2✓ Branch 0 taken 995 times.
✓ Branch 1 taken 556 times.
|
1551 | if (keyuse_1) used_keys.set_bit(keyuse_1->key); |
| 9139 | } | ||
| 9140 | 14547 | } | |
| 9141 | |||
| 9142 |
1/2✓ Branch 0 taken 1504 times.
✗ Branch 1 not taken.
|
1504 | uint new_idx = table->s->find_first_unused_tmp_key( |
| 9143 | used_keys); // Also updates table->s->first_unused_tmp_key. | ||
| 9144 |
2/2✓ Branch 0 taken 530 times.
✓ Branch 1 taken 974 times.
|
1504 | if (keyuse == nullptr) { |
| 9145 | 530 | continue; | |
| 9146 | } | ||
| 9147 | |||
| 9148 | 974 | const uint old_idx = keyuse->key; | |
| 9149 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 974 times.
|
974 | assert(old_idx != new_idx); |
| 9150 | |||
| 9151 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 962 times.
|
974 | if (old_idx > new_idx) { |
| 9152 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | assert(table->s->owner_of_possible_tmp_keys == query_block); |
| 9153 | 12 | it.rewind(); | |
| 9154 |
3/4✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 12 times.
|
25 | while (TABLE *t = it.get_next()) { |
| 9155 | /* | ||
| 9156 | Unlike the collection of used_keys, references from other query | ||
| 9157 | blocks must be considered here, as they need a key_info array | ||
| 9158 | consistent with the to-be-changed table->s->keys. | ||
| 9159 | */ | ||
| 9160 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | t->move_tmp_key(old_idx, it.is_first()); |
| 9161 | 13 | } | |
| 9162 | } else | ||
| 9163 | 962 | new_idx = old_idx; // Index stays at same slot | |
| 9164 | |||
| 9165 | /* | ||
| 9166 | If the key was created by earlier-optimized query blocks, and is | ||
| 9167 | already used by nonlocal references, those don't need any further | ||
| 9168 | update: they are already setup to use it and we're not moving the | ||
| 9169 | key. | ||
| 9170 | If the key was created by this query block, nonlocal references cannot | ||
| 9171 | possibly be referencing it. | ||
| 9172 | In both cases, only local references need to update their Key_use. | ||
| 9173 | */ | ||
| 9174 | 974 | it.rewind(); | |
| 9175 |
3/4✓ Branch 0 taken 14778 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13804 times.
✓ Branch 3 taken 974 times.
|
14778 | while (TABLE *t = it.get_next()) { |
| 9176 |
2/2✓ Branch 0 taken 12807 times.
✓ Branch 1 taken 997 times.
|
13804 | if (t->pos_in_table_list->query_block != query_block) continue; |
| 9177 | 997 | JOIN_TAB *jtab = t->reginfo.join_tab; | |
| 9178 | 997 | Key_use *keyuse_1 = jtab->position()->key; | |
| 9179 |
3/4✓ Branch 0 taken 985 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 985 times.
✗ Branch 3 not taken.
|
997 | if (keyuse_1 && keyuse_1->key == old_idx) { |
| 9180 | 985 | processed_tables |= t->pos_in_table_list->map(); | |
| 9181 | 985 | const bool key_is_const = jtab->const_keys.is_set(old_idx); | |
| 9182 | // tab->keys() was never set, so must be set | ||
| 9183 | 985 | jtab->keys().clear_all(); | |
| 9184 | 985 | jtab->keys().set_bit(new_idx); | |
| 9185 | 985 | jtab->const_keys.clear_all(); | |
| 9186 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 956 times.
|
985 | if (key_is_const) tab->const_keys.set_bit(new_idx); |
| 9187 | 985 | for (Key_use *kit = keyuse_1; | |
| 9188 |
4/4✓ Branch 0 taken 1759 times.
✓ Branch 1 taken 506 times.
✓ Branch 2 taken 1280 times.
✓ Branch 3 taken 479 times.
|
2265 | kit->table_ref == jtab->table_ref && kit->key == old_idx; kit++) |
| 9189 | 1280 | kit->key = new_idx; | |
| 9190 | } | ||
| 9191 | 13804 | } | |
| 9192 | } | ||
| 9193 | } | ||
| 9194 | |||
| 9195 |
2/2✓ Branch 0 taken 175725 times.
✓ Branch 1 taken 1839 times.
|
177564 | if (!adjust_key_count) return; |
| 9196 | |||
| 9197 | // Finally we know how many keys remain in the table. | ||
| 9198 |
2/2✓ Branch 0 taken 6101 times.
✓ Branch 1 taken 1839 times.
|
7940 | for (uint i = 0; i < tables; i++) { |
| 9199 | 6101 | JOIN_TAB *tab = best_ref[i]; | |
| 9200 | 6101 | TABLE *table = tab->table(); | |
| 9201 | 6101 | TABLE_LIST *table_ref = tab->table_ref; | |
| 9202 |
8/8✓ Branch 0 taken 3965 times.
✓ Branch 1 taken 2136 times.
✓ Branch 2 taken 2099 times.
✓ Branch 3 taken 1866 times.
✓ Branch 4 taken 2047 times.
✓ Branch 5 taken 52 times.
✓ Branch 6 taken 2023 times.
✓ Branch 7 taken 4078 times.
|
8148 | if (table && table_ref->uses_materialization() && !table->is_created() && |
| 9203 |
2/2✓ Branch 0 taken 2023 times.
✓ Branch 1 taken 24 times.
|
2047 | table->s->keys > 0) { |
| 9204 |
2/2✓ Branch 0 taken 457 times.
✓ Branch 1 taken 1566 times.
|
2023 | if (table->s->owner_of_possible_tmp_keys != query_block) continue; |
| 9205 | /* | ||
| 9206 | Release lock. As a bonus, avoid double work when this loop | ||
| 9207 | later processes another local reference to the same table (similar to | ||
| 9208 | the processed_tables map in the first loop). | ||
| 9209 | */ | ||
| 9210 | 1566 | table->s->owner_of_possible_tmp_keys = nullptr; | |
| 9211 | 1566 | Derived_refs_iterator it(table_ref); | |
| 9212 |
4/6✓ Branch 0 taken 23521 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21955 times.
✓ Branch 3 taken 1566 times.
✓ Branch 4 taken 21955 times.
✗ Branch 5 not taken.
|
23521 | while (TABLE *t = it.get_next()) t->drop_unused_tmp_keys(it.is_first()); |
| 9213 | } | ||
| 9214 | } | ||
| 9215 | } | ||
| 9216 | |||
| 9217 | /** | ||
| 9218 | @brief | ||
| 9219 | Extract a condition that can be checked after reading given table | ||
| 9220 | |||
| 9221 | @param thd Current session. | ||
| 9222 | @param cond Condition to analyze | ||
| 9223 | @param tables Tables for which "current field values" are available | ||
| 9224 | @param used_table Table(s) that we are extracting the condition for (may | ||
| 9225 | also include PSEUDO_TABLE_BITS, and may be zero) | ||
| 9226 | @param exclude_expensive_cond Do not push expensive conditions | ||
| 9227 | |||
| 9228 | @retval <>NULL Generated condition | ||
| 9229 | @retval = NULL Already checked, OR error | ||
| 9230 | |||
| 9231 | @details | ||
| 9232 | Extract the condition that can be checked after reading the table(s) | ||
| 9233 | specified in @c used_table, given that current-field values for tables | ||
| 9234 | specified in @c tables bitmap are available. | ||
| 9235 | If @c used_table is 0, extract conditions for all tables in @c tables. | ||
| 9236 | |||
| 9237 | This function can be used to extract conditions relevant for a table | ||
| 9238 | in a join order. Together with its caller, it will ensure that all | ||
| 9239 | conditions are attached to the first table in the join order where all | ||
| 9240 | necessary fields are available, and it will also ensure that a given | ||
| 9241 | condition is attached to only one table. | ||
| 9242 | To accomplish this, first initialize @c tables to the empty | ||
| 9243 | set. Then, loop over all tables in the join order, set @c used_table to | ||
| 9244 | the bit representing the current table, accumulate @c used_table into the | ||
| 9245 | @c tables set, and call this function. To ensure correct handling of | ||
| 9246 | const expressions and outer references, add the const table map and | ||
| 9247 | OUTER_REF_TABLE_BIT to @c used_table for the first table. To ensure | ||
| 9248 | that random expressions are evaluated for the final table, add | ||
| 9249 | RAND_TABLE_BIT to @c used_table for the final table. | ||
| 9250 | |||
| 9251 | The function assumes that constant, inexpensive parts of the condition | ||
| 9252 | have already been checked. Constant, expensive parts will be attached | ||
| 9253 | to the first table in the join order, provided that the above call | ||
| 9254 | sequence is followed. | ||
| 9255 | |||
| 9256 | The call order will ensure that conditions covering tables in @c tables | ||
| 9257 | minus those in @c used_table, have already been checked. | ||
| 9258 | |||
| 9259 | The function takes into account that some parts of the condition are | ||
| 9260 | guaranteed to be true by employed 'ref' access methods (the code that | ||
| 9261 | does this is located at the end, search down for "EQ_FUNC"). | ||
| 9262 | |||
| 9263 | @note | ||
| 9264 | make_cond_for_info_schema() uses an algorithm similar to | ||
| 9265 | make_cond_for_table(). | ||
| 9266 | */ | ||
| 9267 | |||
| 9268 | 25287429 | Item *make_cond_for_table(THD *thd, Item *cond, table_map tables, | |
| 9269 | table_map used_table, bool exclude_expensive_cond) { | ||
| 9270 | /* | ||
| 9271 | May encounter an Item_cache_int as "condition" here, so cannot | ||
| 9272 | assert that it satisfies is_bool_func(). | ||
| 9273 | */ | ||
| 9274 | /* | ||
| 9275 | Ignore this condition if | ||
| 9276 | 1. We are extracting conditions for a specific table, and | ||
| 9277 | 2. that table is not referenced by the condition, but not if | ||
| 9278 | 3. this is a constant condition not checked at optimization time and | ||
| 9279 | this is the first table we are extracting conditions for. | ||
| 9280 | (Assuming that used_table == tables for the first table.) | ||
| 9281 | */ | ||
| 9282 | 45097712 | if (used_table && // 1 | |
| 9283 |
6/6✓ Branch 0 taken 19810130 times.
✓ Branch 1 taken 5477299 times.
✓ Branch 2 taken 11013945 times.
✓ Branch 3 taken 8796194 times.
✓ Branch 4 taken 11014045 times.
✓ Branch 5 taken 14273528 times.
|
36301509 | !(cond->used_tables() & used_table) && // 2 |
| 9284 |
4/4✓ Branch 0 taken 108 times.
✓ Branch 1 taken 11013972 times.
✓ Branch 2 taken 68 times.
✓ Branch 3 taken 40 times.
|
11013945 | !(cond->is_expensive() && used_table == tables)) // 3 |
| 9285 | 11014045 | return nullptr; | |
| 9286 | |||
| 9287 |
2/2✓ Branch 0 taken 3132645 times.
✓ Branch 1 taken 11140974 times.
|
14273528 | if (cond->type() == Item::COND_ITEM) { |
| 9288 |
2/2✓ Branch 0 taken 3086308 times.
✓ Branch 1 taken 46380 times.
|
3132645 | if (((Item_cond *)cond)->functype() == Item_func::COND_AND_FUNC) { |
| 9289 | /* Create new top level AND item */ | ||
| 9290 |
2/4✓ Branch 0 taken 3086210 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3086312 times.
✗ Branch 3 not taken.
|
3086308 | Item_cond_and *new_cond = new Item_cond_and; |
| 9291 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3086312 times.
|
3086312 | if (!new_cond) return nullptr; |
| 9292 |
1/2✓ Branch 0 taken 3086318 times.
✗ Branch 1 not taken.
|
3086312 | List_iterator<Item> li(*((Item_cond *)cond)->argument_list()); |
| 9293 | Item *item; | ||
| 9294 |
2/2✓ Branch 0 taken 19794527 times.
✓ Branch 1 taken 3086044 times.
|
22880752 | while ((item = li++)) { |
| 9295 |
1/2✓ Branch 0 taken 19794503 times.
✗ Branch 1 not taken.
|
19794527 | Item *fix = make_cond_for_table(thd, item, tables, used_table, |
| 9296 | exclude_expensive_cond); | ||
| 9297 |
3/4✓ Branch 0 taken 3662221 times.
✓ Branch 1 taken 16132282 times.
✓ Branch 2 taken 3662152 times.
✗ Branch 3 not taken.
|
19794503 | if (fix) new_cond->argument_list()->push_back(fix); |
| 9298 | } | ||
| 9299 |
3/3✓ Branch 0 taken 1236672 times.
✓ Branch 1 taken 811368 times.
✓ Branch 2 taken 1038262 times.
|
3086044 | switch (new_cond->argument_list()->elements) { |
| 9300 | 1236672 | case 0: | |
| 9301 | 1236672 | return nullptr; // Always true | |
| 9302 | 811368 | case 1: | |
| 9303 | 811368 | return new_cond->argument_list()->head(); | |
| 9304 | 1038262 | default: | |
| 9305 |
2/4✓ Branch 0 taken 1038192 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1038192 times.
|
1038262 | if (new_cond->fix_fields(thd, nullptr)) return nullptr; |
| 9306 | 1038192 | return new_cond; | |
| 9307 | } | ||
| 9308 | } else { // Or list | ||
| 9309 |
2/4✓ Branch 0 taken 46388 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46388 times.
✗ Branch 3 not taken.
|
46380 | Item_cond_or *new_cond = new Item_cond_or; |
| 9310 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46388 times.
|
46388 | if (!new_cond) return nullptr; |
| 9311 |
1/2✓ Branch 0 taken 46388 times.
✗ Branch 1 not taken.
|
46388 | List_iterator<Item> li(*((Item_cond *)cond)->argument_list()); |
| 9312 | Item *item; | ||
| 9313 |
2/2✓ Branch 0 taken 85854 times.
✓ Branch 1 taken 22885 times.
|
108739 | while ((item = li++)) { |
| 9314 |
1/2✓ Branch 0 taken 85854 times.
✗ Branch 1 not taken.
|
85854 | Item *fix = make_cond_for_table(thd, item, tables, table_map(0), |
| 9315 | exclude_expensive_cond); | ||
| 9316 |
2/2✓ Branch 0 taken 23503 times.
✓ Branch 1 taken 62351 times.
|
85854 | if (!fix) return nullptr; // Always true |
| 9317 |
1/2✓ Branch 0 taken 62351 times.
✗ Branch 1 not taken.
|
62351 | new_cond->argument_list()->push_back(fix); |
| 9318 | } | ||
| 9319 |
2/4✓ Branch 0 taken 22885 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22885 times.
|
22885 | if (new_cond->fix_fields(thd, nullptr)) return nullptr; |
| 9320 | 22885 | return new_cond; | |
| 9321 | } | ||
| 9322 | } | ||
| 9323 | |||
| 9324 | /* | ||
| 9325 | Omit this condition if | ||
| 9326 | 1. Some tables referred by the condition are not available, or | ||
| 9327 | 2. We are extracting conditions for all tables, the condition is | ||
| 9328 | considered 'expensive', and we want to delay evaluation of such | ||
| 9329 | conditions to the execution phase. | ||
| 9330 | */ | ||
| 9331 |
6/6✓ Branch 0 taken 4622281 times.
✓ Branch 1 taken 6518671 times.
✓ Branch 2 taken 152322 times.
✓ Branch 3 taken 4469959 times.
✓ Branch 4 taken 6518779 times.
✓ Branch 5 taken 4622173 times.
|
11293296 | if ((cond->used_tables() & ~tables) || // 1 |
| 9332 |
4/4✓ Branch 0 taken 86601 times.
✓ Branch 1 taken 65721 times.
✓ Branch 2 taken 89 times.
✓ Branch 3 taken 86512 times.
|
152322 | (!used_table && exclude_expensive_cond && cond->is_expensive())) // 2 |
| 9333 | 6518779 | return nullptr; | |
| 9334 | |||
| 9335 | 4622173 | return cond; | |
| 9336 | } | ||
| 9337 | |||
| 9338 | /** | ||
| 9339 | Separates the predicates in a join condition and pushes them to the | ||
| 9340 | join step where all involved tables are available in the join prefix. | ||
| 9341 | ON clauses from JOIN expressions are also pushed to the most appropriate step. | ||
| 9342 | |||
| 9343 | @param join Join object where predicates are pushed. | ||
| 9344 | |||
| 9345 | @param cond Pointer to condition which may contain an arbitrary number of | ||
| 9346 | predicates, combined using AND, OR and XOR items. | ||
| 9347 | If NULL, equivalent to a predicate that returns true for all | ||
| 9348 | row combinations. | ||
| 9349 | |||
| 9350 | |||
| 9351 | @retval true Found impossible WHERE clause, or out-of-memory | ||
| 9352 | @retval false Other | ||
| 9353 | */ | ||
| 9354 | |||
| 9355 | 1816566 | static bool make_join_query_block(JOIN *join, Item *cond) { | |
| 9356 |
4/6✓ Branch 0 taken 1191824 times.
✓ Branch 1 taken 624742 times.
✓ Branch 2 taken 1191860 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1191860 times.
|
1816566 | assert(cond == nullptr || cond->is_bool_func()); |
| 9357 | 1816602 | THD *thd = join->thd; | |
| 9358 | 1816602 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 9359 |
1/2✓ Branch 0 taken 1816637 times.
✗ Branch 1 not taken.
|
1816602 | DBUG_TRACE; |
| 9360 |
4/6✓ Branch 0 taken 1816638 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1816636 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1816636 times.
✗ Branch 5 not taken.
|
1816637 | ASSERT_BEST_REF_IN_JOIN_ORDER(join); |
| 9361 | |||
| 9362 | // Add IS NOT NULL conditions to table conditions: | ||
| 9363 |
2/4✓ Branch 0 taken 1816640 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1816640 times.
|
1816635 | if (add_not_null_conds(join)) return true; |
| 9364 | |||
| 9365 | /* | ||
| 9366 | Extract constant conditions that are part of the WHERE clause. | ||
| 9367 | Constant parts of join conditions from outer joins are attached to | ||
| 9368 | the appropriate table condition in JOIN::attach_join_conditions(). | ||
| 9369 | */ | ||
| 9370 |
2/2✓ Branch 0 taken 1191888 times.
✓ Branch 1 taken 624752 times.
|
1816640 | if (cond) /* Because of GroupIndexSkipScanIterator */ |
| 9371 | { /* there may be a select without a cond. */ | ||
| 9372 |
2/2✓ Branch 0 taken 446922 times.
✓ Branch 1 taken 744966 times.
|
1191888 | if (join->primary_tables > 1) |
| 9373 |
1/2✓ Branch 0 taken 446921 times.
✗ Branch 1 not taken.
|
446922 | cond->update_used_tables(); // Table number may have changed |
| 9374 |
4/4✓ Branch 0 taken 78589 times.
✓ Branch 1 taken 1113302 times.
✓ Branch 2 taken 77294 times.
✓ Branch 3 taken 1114597 times.
|
1270476 | if (join->plan_is_const() && |
| 9375 | 78589 | join->query_block->master_query_expression() == | |
| 9376 |
2/2✓ Branch 0 taken 77294 times.
✓ Branch 1 taken 1295 times.
|
78589 | thd->lex->unit) // The outer-most query block |
| 9377 | 77294 | join->const_table_map |= RAND_TABLE_BIT; | |
| 9378 | } | ||
| 9379 | /* | ||
| 9380 | Extract conditions that depend on constant tables. | ||
| 9381 | The const part of the query's WHERE clause can be checked immediately | ||
| 9382 | and if it is not satisfied then the join has empty result | ||
| 9383 | */ | ||
| 9384 | 1816643 | Item *const_cond = nullptr; | |
| 9385 |
2/2✓ Branch 0 taken 1191891 times.
✓ Branch 1 taken 624752 times.
|
1816643 | if (cond) |
| 9386 |
1/2✓ Branch 0 taken 1191870 times.
✗ Branch 1 not taken.
|
1191891 | const_cond = make_cond_for_table(thd, cond, join->const_table_map, |
| 9387 | table_map(0), true); | ||
| 9388 | |||
| 9389 | // Add conditions added by add_not_null_conds() | ||
| 9390 |
2/2✓ Branch 0 taken 90074 times.
✓ Branch 1 taken 1816622 times.
|
1906696 | for (uint i = 0; i < join->const_tables; i++) { |
| 9391 |
2/4✓ Branch 0 taken 90074 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 90074 times.
|
90074 | if (and_conditions(&const_cond, join->best_ref[i]->condition())) |
| 9392 | ✗ | return true; | |
| 9393 | } | ||
| 9394 |
3/6✓ Branch 0 taken 1816624 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 1816598 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1816622 | DBUG_EXECUTE("where", |
| 9395 | print_where(thd, const_cond, "constants", QT_ORDINARY);); | ||
| 9396 |
4/4✓ Branch 0 taken 84423 times.
✓ Branch 1 taken 1732114 times.
✓ Branch 2 taken 84423 times.
✓ Branch 3 taken 1732114 times.
|
1900960 | if (const_cond != nullptr && |
| 9397 |
2/4✓ Branch 0 taken 84423 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84423 times.
✗ Branch 3 not taken.
|
84423 | evaluate_during_optimization(const_cond, join->query_block)) { |
| 9398 |
1/2✓ Branch 0 taken 84423 times.
✗ Branch 1 not taken.
|
84423 | const bool const_cond_result = const_cond->val_int() != 0; |
| 9399 |
3/4✓ Branch 0 taken 84423 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 84421 times.
|
86429 | if (thd->is_error()) return true; |
| 9400 | |||
| 9401 |
1/2✓ Branch 0 taken 84421 times.
✗ Branch 1 not taken.
|
84421 | Opt_trace_object trace_const_cond(trace); |
| 9402 | 168842 | trace_const_cond.add("condition_on_constant_tables", const_cond) | |
| 9403 |
2/4✓ Branch 0 taken 84421 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84421 times.
✗ Branch 3 not taken.
|
84421 | .add("condition_value", const_cond_result); |
| 9404 |
2/2✓ Branch 0 taken 82415 times.
✓ Branch 1 taken 2006 times.
|
84421 | if (const_cond_result) { |
| 9405 | /* | ||
| 9406 | If all the tables referred by the condition are const tables and | ||
| 9407 | if the condition is not expensive, we can remove the where condition | ||
| 9408 | as it will always evaluate to "true". | ||
| 9409 | */ | ||
| 9410 | 82415 | if (join->plan_is_const() && | |
| 9411 |
7/8✓ Branch 0 taken 76490 times.
✓ Branch 1 taken 5925 times.
✓ Branch 2 taken 76490 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 76487 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 76486 times.
✓ Branch 7 taken 5929 times.
|
158902 | !(cond->used_tables() & ~join->const_table_map) && |
| 9412 |
3/4✓ Branch 0 taken 76487 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 76486 times.
✓ Branch 3 taken 1 times.
|
76487 | !cond->is_expensive()) { |
| 9413 |
3/8✓ Branch 0 taken 76486 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 76486 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 76486 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
76486 | DBUG_PRINT("info", ("Found always true WHERE condition")); |
| 9414 | 76486 | join->where_cond = nullptr; | |
| 9415 | } | ||
| 9416 | } else { | ||
| 9417 |
3/8✓ Branch 0 taken 2006 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2006 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2006 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
2006 | DBUG_PRINT("info", ("Found impossible WHERE condition")); |
| 9418 | 2006 | return true; | |
| 9419 | } | ||
| 9420 |
2/2✓ Branch 0 taken 82415 times.
✓ Branch 1 taken 2006 times.
|
84421 | } |
| 9421 | |||
| 9422 | /* | ||
| 9423 | Extract remaining conditions from WHERE clause and join conditions, | ||
| 9424 | and attach them to the most appropriate table condition. This means that | ||
| 9425 | a condition will be evaluated as soon as all fields it depends on are | ||
| 9426 | available. For outer join conditions, the additional criterion is that | ||
| 9427 | we must have determined whether outer-joined rows are available, or | ||
| 9428 | have been NULL-extended, see JOIN::attach_join_conditions() for details. | ||
| 9429 | */ | ||
| 9430 | { | ||
| 9431 |
1/2✓ Branch 0 taken 1814544 times.
✗ Branch 1 not taken.
|
1814529 | Opt_trace_object trace_wrapper(trace); |
| 9432 |
1/2✓ Branch 0 taken 1814622 times.
✗ Branch 1 not taken.
|
1814544 | Opt_trace_object trace_conditions(trace, "attaching_conditions_to_tables"); |
| 9433 |
1/2✓ Branch 0 taken 1814605 times.
✗ Branch 1 not taken.
|
1814622 | trace_conditions.add("original_condition", cond); |
| 9434 | Opt_trace_array trace_attached_comp(trace, | ||
| 9435 |
1/2✓ Branch 0 taken 1814618 times.
✗ Branch 1 not taken.
|
1814605 | "attached_conditions_computation"); |
| 9436 | |||
| 9437 |
2/2✓ Branch 0 taken 6165099 times.
✓ Branch 1 taken 1814715 times.
|
7979814 | for (uint i = join->const_tables; i < join->tables; i++) { |
| 9438 | 6165099 | JOIN_TAB *const tab = join->best_ref[i]; | |
| 9439 | |||
| 9440 |
2/2✓ Branch 0 taken 2385461 times.
✓ Branch 1 taken 3779773 times.
|
6165099 | if (!tab->position()) continue; |
| 9441 | /* | ||
| 9442 | first_inner is the X in queries like: | ||
| 9443 | SELECT * FROM t1 LEFT OUTER JOIN (t2 JOIN t3) ON X | ||
| 9444 | */ | ||
| 9445 | 3779773 | const plan_idx first_inner = tab->first_inner(); | |
| 9446 | 3779818 | const table_map used_tables = tab->prefix_tables(); | |
| 9447 | 3779818 | const table_map current_map = tab->added_tables(); | |
| 9448 | 3779830 | Item *tmp = nullptr; | |
| 9449 | |||
| 9450 |
2/2✓ Branch 0 taken 3146705 times.
✓ Branch 1 taken 633125 times.
|
3779830 | if (cond) |
| 9451 |
1/2✓ Branch 0 taken 3146674 times.
✗ Branch 1 not taken.
|
3146705 | tmp = make_cond_for_table(thd, cond, used_tables, current_map, false); |
| 9452 | /* Add conditions added by add_not_null_conds(). */ | ||
| 9453 |
2/4✓ Branch 0 taken 3779715 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3779715 times.
|
3779802 | if (and_conditions(&tmp, tab->condition())) return true; |
| 9454 | |||
| 9455 |
8/8✓ Branch 0 taken 3146645 times.
✓ Branch 1 taken 633070 times.
✓ Branch 2 taken 987690 times.
✓ Branch 3 taken 2158955 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 987745 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 3779770 times.
|
3779715 | if (cond && !tmp && tab->range_scan()) { // Outer join |
| 9456 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | assert(tab->type() == JT_RANGE || tab->type() == JT_INDEX_MERGE); |
| 9457 | /* | ||
| 9458 | Hack to handle the case where we only refer to a table | ||
| 9459 | in the ON part of an OUTER JOIN. In this case we want the code | ||
| 9460 | below to check if we should use 'quick' instead. | ||
| 9461 | */ | ||
| 9462 |
3/8✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
2 | DBUG_PRINT("info", ("Item_func_true")); |
| 9463 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | tmp = new Item_func_true(); // Always true |
| 9464 | } | ||
| 9465 |
5/6✓ Branch 0 taken 987693 times.
✓ Branch 1 taken 633109 times.
✓ Branch 2 taken 984967 times.
✓ Branch 3 taken 2726 times.
✓ Branch 4 taken 985005 times.
✗ Branch 5 not taken.
|
2605803 | if (tmp || !cond || tab->type() == JT_REF || |
| 9466 |
8/8✓ Branch 0 taken 1620802 times.
✓ Branch 1 taken 2158970 times.
✓ Branch 2 taken 473075 times.
✓ Branch 3 taken 511924 times.
✓ Branch 4 taken 15283 times.
✓ Branch 5 taken 457792 times.
✓ Branch 6 taken 3322010 times.
✓ Branch 7 taken 457790 times.
|
6385575 | tab->type() == JT_REF_OR_NULL || tab->type() == JT_EQ_REF || |
| 9467 | first_inner != NO_PLAN_IDX) { | ||
| 9468 |
4/6✓ Branch 0 taken 3321972 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 3321946 times.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
|
3322010 | DBUG_EXECUTE("where", |
| 9469 | print_where(thd, tmp, tab->table()->alias, QT_ORDINARY);); | ||
| 9470 | /* | ||
| 9471 | If tab is an inner table of an outer join operation, | ||
| 9472 | add a match guard to the pushed down predicate. | ||
| 9473 | The guard will turn the predicate on only after | ||
| 9474 | the first match for outer tables is encountered. | ||
| 9475 | */ | ||
| 9476 |
4/4✓ Branch 0 taken 2688845 times.
✓ Branch 1 taken 633128 times.
✓ Branch 2 taken 2158916 times.
✓ Branch 3 taken 529929 times.
|
3321973 | if (cond && tmp) { |
| 9477 | /* | ||
| 9478 | Because of GroupIndexSkipScanIterator there may be a select without | ||
| 9479 | a cond, so neutralize the hack above. | ||
| 9480 | */ | ||
| 9481 |
2/4✓ Branch 0 taken 2158822 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2158822 times.
|
2158916 | if (!(tmp = add_found_match_trig_cond(join, first_inner, tmp, |
| 9482 | NO_PLAN_IDX))) | ||
| 9483 | ✗ | return true; | |
| 9484 | 2158822 | tab->set_condition(tmp); | |
| 9485 | } else { | ||
| 9486 | 1163057 | tab->set_condition(nullptr); | |
| 9487 | } | ||
| 9488 | |||
| 9489 |
4/6✓ Branch 0 taken 3321964 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 3321938 times.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
|
3321983 | DBUG_EXECUTE("where", |
| 9490 | print_where(thd, tmp, tab->table()->alias, QT_ORDINARY);); | ||
| 9491 | |||
| 9492 |
2/2✓ Branch 0 taken 33913 times.
✓ Branch 1 taken 3288078 times.
|
3321964 | if (tab->range_scan()) { |
| 9493 |
3/6✓ Branch 0 taken 33913 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33913 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 33913 times.
|
33913 | if (tab->needed_reg.is_clear_all() && tab->type() != JT_CONST) { |
| 9494 | /* | ||
| 9495 | We keep (for now) the QUICK AM calculated in | ||
| 9496 | get_quick_record_count(). | ||
| 9497 | */ | ||
| 9498 | } else { | ||
| 9499 | ✗ | destroy(tab->range_scan()); | |
| 9500 | ✗ | tab->set_range_scan(nullptr); | |
| 9501 | } | ||
| 9502 | } | ||
| 9503 | |||
| 9504 |
4/4✓ Branch 0 taken 1989012 times.
✓ Branch 1 taken 33041 times.
✓ Branch 2 taken 1988149 times.
✓ Branch 3 taken 872 times.
|
7333082 | if ((tab->type() == JT_ALL || tab->type() == JT_RANGE || |
| 9505 |
6/6✓ Branch 0 taken 2022070 times.
✓ Branch 1 taken 1299918 times.
✓ Branch 2 taken 49440 times.
✓ Branch 3 taken 1938726 times.
✓ Branch 4 taken 1382254 times.
✓ Branch 5 taken 1939743 times.
|
8682420 | tab->type() == JT_INDEX_MERGE || tab->type() == JT_INDEX_SCAN) && |
| 9506 |
2/2✓ Branch 0 taken 1382254 times.
✓ Branch 1 taken 1017 times.
|
1383271 | tab->use_quick != QS_RANGE) { |
| 9507 | /* | ||
| 9508 | We plan to scan (table/index/range scan). | ||
| 9509 | Check again if we should use an index. We can use an index if: | ||
| 9510 | |||
| 9511 | 1a) There is a condition that range optimizer can work on, and | ||
| 9512 | 1b) There are non-constant conditions on one or more keys, and | ||
| 9513 | 1c) Some of the non-constant fields may have been read | ||
| 9514 | already. This may be the case if this is not the first | ||
| 9515 | table in the join OR this is a subselect with | ||
| 9516 | non-constant conditions referring to an outer table | ||
| 9517 | (dependent subquery) | ||
| 9518 | or, | ||
| 9519 | 2a) There are conditions only relying on constants | ||
| 9520 | 2b) This is the first non-constant table | ||
| 9521 | 2c) There is a limit of rows to read that is lower than | ||
| 9522 | the fanout for this table, predicate filters included | ||
| 9523 | (i.e., the estimated number of rows that will be | ||
| 9524 | produced for this table per row combination of | ||
| 9525 | previous tables) | ||
| 9526 | 2d) The query is NOT run with FOUND_ROWS() (because in that | ||
| 9527 | case we have to scan through all rows to count them anyway) | ||
| 9528 | */ | ||
| 9529 | enum { | ||
| 9530 | DONT_RECHECK, | ||
| 9531 | NOT_FIRST_TABLE, | ||
| 9532 | LOW_LIMIT | ||
| 9533 | 1382254 | } recheck_reason = DONT_RECHECK; | |
| 9534 | |||
| 9535 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1382254 times.
|
1382254 | assert(tab->const_keys.is_subset(tab->keys())); |
| 9536 | |||
| 9537 | 1382254 | const join_type orig_join_type = tab->type(); | |
| 9538 | 1382254 | const AccessPath *const orig_range_scan = tab->range_scan(); | |
| 9539 | |||
| 9540 |
2/2✓ Branch 0 taken 60293 times.
✓ Branch 1 taken 688873 times.
|
749166 | if (cond && // 1a |
| 9541 |
6/6✓ Branch 0 taken 749166 times.
✓ Branch 1 taken 633088 times.
✓ Branch 2 taken 4610 times.
✓ Branch 3 taken 55683 times.
✓ Branch 4 taken 56189 times.
✓ Branch 5 taken 1326065 times.
|
2136030 | (tab->keys() != tab->const_keys) && // 1b |
| 9542 | 4610 | (i > 0 || // 1c | |
| 9543 |
2/2✓ Branch 0 taken 776 times.
✓ Branch 1 taken 3834 times.
|
4610 | (join->query_block->master_query_expression()->item && |
| 9544 |
3/4✓ Branch 0 taken 776 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 506 times.
✓ Branch 3 taken 270 times.
|
776 | cond->is_outer_reference()))) |
| 9545 | 56189 | recheck_reason = NOT_FIRST_TABLE; | |
| 9546 | 1326065 | else if (!tab->const_keys.is_clear_all() && // 2a | |
| 9547 |
2/2✓ Branch 0 taken 240568 times.
✓ Branch 1 taken 894 times.
|
241462 | i == join->const_tables && // 2b |
| 9548 | 240568 | (join->query_expression()->select_limit_cnt < | |
| 9549 | 240568 | (tab->position()->rows_fetched * | |
| 9550 |
6/6✓ Branch 0 taken 241462 times.
✓ Branch 1 taken 1084603 times.
✓ Branch 2 taken 2748 times.
✓ Branch 3 taken 237820 times.
✓ Branch 4 taken 2743 times.
✓ Branch 5 taken 1323322 times.
|
1570275 | tab->position()->filter_effect)) && // 2c |
| 9551 |
2/2✓ Branch 0 taken 2743 times.
✓ Branch 1 taken 5 times.
|
2748 | !join->calc_found_rows) // 2d |
| 9552 | 2743 | recheck_reason = LOW_LIMIT; | |
| 9553 | |||
| 9554 | // Don't recheck if the storage engine does not support index access. | ||
| 9555 |
2/2✓ Branch 0 taken 308 times.
✓ Branch 1 taken 1381946 times.
|
1382254 | if ((tab->table()->file->ha_table_flags() & HA_NO_INDEX_ACCESS) != 0) |
| 9556 | 308 | recheck_reason = DONT_RECHECK; | |
| 9557 | |||
| 9558 |
2/2✓ Branch 0 taken 186 times.
✓ Branch 1 taken 1382068 times.
|
1382254 | if (tab->position()->sj_strategy == SJ_OPT_LOOSE_SCAN) { |
| 9559 | /* | ||
| 9560 | Semijoin loose scan has settled for a certain index-based access | ||
| 9561 | method with suitable characteristics, don't substitute it. | ||
| 9562 | */ | ||
| 9563 | 186 | recheck_reason = DONT_RECHECK; | |
| 9564 | } | ||
| 9565 | |||
| 9566 |
2/2✓ Branch 0 taken 58894 times.
✓ Branch 1 taken 1323360 times.
|
1382254 | if (recheck_reason != DONT_RECHECK) { |
| 9567 |
1/2✓ Branch 0 taken 58894 times.
✗ Branch 1 not taken.
|
58894 | Opt_trace_object trace_one_table(trace); |
| 9568 |
1/2✓ Branch 0 taken 58894 times.
✗ Branch 1 not taken.
|
58894 | trace_one_table.add_utf8_table(tab->table_ref); |
| 9569 |
1/2✓ Branch 0 taken 58894 times.
✗ Branch 1 not taken.
|
58894 | Opt_trace_object trace_table(trace, "rechecking_index_usage"); |
| 9570 |
2/2✓ Branch 0 taken 56151 times.
✓ Branch 1 taken 2743 times.
|
58894 | if (recheck_reason == NOT_FIRST_TABLE) |
| 9571 |
1/2✓ Branch 0 taken 56151 times.
✗ Branch 1 not taken.
|
56151 | trace_table.add_alnum("recheck_reason", "not_first_table"); |
| 9572 | else | ||
| 9573 |
1/2✓ Branch 0 taken 2743 times.
✗ Branch 1 not taken.
|
2743 | trace_table.add_alnum("recheck_reason", "low_limit") |
| 9574 |
1/2✓ Branch 0 taken 2743 times.
✗ Branch 1 not taken.
|
2743 | .add("limit", join->query_expression()->select_limit_cnt) |
| 9575 | 2743 | .add("row_estimate", tab->position()->rows_fetched * | |
| 9576 |
1/2✓ Branch 0 taken 2743 times.
✗ Branch 1 not taken.
|
2743 | tab->position()->filter_effect); |
| 9577 | |||
| 9578 | /* Join with outer join condition */ | ||
| 9579 | 58894 | Item *orig_cond = tab->condition(); | |
| 9580 |
1/2✓ Branch 0 taken 58894 times.
✗ Branch 1 not taken.
|
58894 | tab->and_with_condition(tab->join_cond()); |
| 9581 | |||
| 9582 | /* | ||
| 9583 | We can't call sel->cond->fix_fields, | ||
| 9584 | as it will break tab->join_cond() if it's AND condition | ||
| 9585 | (fix_fields currently removes extra AND/OR levels). | ||
| 9586 | Yet attributes of the just built condition are not needed. | ||
| 9587 | Thus we call sel->cond->quick_fix_field for safety. | ||
| 9588 | */ | ||
| 9589 |
4/6✓ Branch 0 taken 58327 times.
✓ Branch 1 taken 567 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 58327 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 58894 times.
|
58894 | if (tab->condition() && !tab->condition()->fixed) |
| 9590 | ✗ | tab->condition()->quick_fix_field(); | |
| 9591 | |||
| 9592 | 58894 | Key_map usable_keys = tab->keys(); | |
| 9593 | 58894 | enum_order interesting_order = ORDER_NOT_RELEVANT; | |
| 9594 | |||
| 9595 |
2/2✓ Branch 0 taken 2743 times.
✓ Branch 1 taken 56151 times.
|
58894 | if (recheck_reason == LOW_LIMIT) { |
| 9596 | 2743 | int read_direction = 0; | |
| 9597 | |||
| 9598 | /* | ||
| 9599 | If the current plan is to use range, then check if the | ||
| 9600 | already selected index provides the order dictated by the | ||
| 9601 | ORDER BY clause. | ||
| 9602 | */ | ||
| 9603 |
6/6✓ Branch 0 taken 1474 times.
✓ Branch 1 taken 1269 times.
✓ Branch 2 taken 1472 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1472 times.
✓ Branch 5 taken 1271 times.
|
4217 | if (tab->range_scan() && |
| 9604 | 1474 | used_index(tab->range_scan()) != MAX_KEY) { | |
| 9605 | 1472 | const uint ref_key = used_index(tab->range_scan()); | |
| 9606 | bool skip_quick; | ||
| 9607 |
1/2✓ Branch 0 taken 1472 times.
✗ Branch 1 not taken.
|
1472 | read_direction = test_if_order_by_key( |
| 9608 | &join->order, tab->table(), ref_key, nullptr, &skip_quick); | ||
| 9609 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1472 times.
|
1472 | if (skip_quick) read_direction = 0; |
| 9610 | /* | ||
| 9611 | If the index provides order there is no need to recheck | ||
| 9612 | index usage; we already know from the former call to | ||
| 9613 | test_quick_select() that a range scan on the chosen | ||
| 9614 | index is cheapest. Note that previous calls to | ||
| 9615 | test_quick_select() did not take order direction | ||
| 9616 | (ASC/DESC) into account, so in case of DESC ordering | ||
| 9617 | we still need to recheck. | ||
| 9618 | */ | ||
| 9619 |
4/4✓ Branch 0 taken 767 times.
✓ Branch 1 taken 705 times.
✓ Branch 2 taken 705 times.
✓ Branch 3 taken 767 times.
|
2239 | if (read_direction == 1 || |
| 9620 |
3/4✓ Branch 0 taken 319 times.
✓ Branch 1 taken 448 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 319 times.
|
1086 | (read_direction == -1 && |
| 9621 | 319 | is_reverse_sorted_range(tab->range_scan()))) { | |
| 9622 | 705 | recheck_reason = DONT_RECHECK; | |
| 9623 | } | ||
| 9624 | } | ||
| 9625 | // We do a cost based search for an ordering index here. Do this | ||
| 9626 | // only if prefer_ordering_index switch is on or an index is | ||
| 9627 | // forced for order by | ||
| 9628 |
4/4✓ Branch 0 taken 2038 times.
✓ Branch 1 taken 705 times.
✓ Branch 2 taken 2036 times.
✓ Branch 3 taken 707 times.
|
4781 | if (recheck_reason != DONT_RECHECK && |
| 9629 |
4/4✓ Branch 0 taken 2036 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2034 times.
✓ Branch 3 taken 2 times.
|
4074 | (tab->table()->force_index_order || |
| 9630 | 2036 | thd->optimizer_switch_flag( | |
| 9631 | OPTIMIZER_SWITCH_PREFER_ORDERING_INDEX))) { | ||
| 9632 | 2036 | int best_key = -1; | |
| 9633 | ha_rows select_limit = | ||
| 9634 | 2036 | join->query_expression()->select_limit_cnt; | |
| 9635 | |||
| 9636 | /* Use index specified in FORCE INDEX FOR ORDER BY, if any. */ | ||
| 9637 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2034 times.
|
2036 | if (tab->table()->force_index_order) |
| 9638 | 2 | usable_keys.intersect(tab->table()->keys_in_use_for_order_by); | |
| 9639 | |||
| 9640 | // Do a cost based search on the indexes that give sort order. | ||
| 9641 |
1/2✓ Branch 0 taken 2036 times.
✗ Branch 1 not taken.
|
2036 | test_if_cheaper_ordering( |
| 9642 | tab, &join->order, tab->table(), usable_keys, -1, | ||
| 9643 | select_limit, &best_key, &read_direction, &select_limit); | ||
| 9644 |
2/2✓ Branch 0 taken 1100 times.
✓ Branch 1 taken 936 times.
|
2036 | if (best_key < 0) |
| 9645 | 1100 | recheck_reason = DONT_RECHECK; // No usable keys | |
| 9646 | else { | ||
| 9647 | // Only usable_key is the best_key chosen | ||
| 9648 | 936 | usable_keys.clear_all(); | |
| 9649 | 936 | usable_keys.set_bit(best_key); | |
| 9650 | 936 | interesting_order = | |
| 9651 |
2/2✓ Branch 0 taken 376 times.
✓ Branch 1 taken 560 times.
|
936 | (read_direction == -1 ? ORDER_DESC : ORDER_ASC); |
| 9652 | } | ||
| 9653 | } | ||
| 9654 | } | ||
| 9655 | |||
| 9656 | 58894 | bool search_if_impossible = recheck_reason != DONT_RECHECK; | |
| 9657 |
2/2✓ Branch 0 taken 57089 times.
✓ Branch 1 taken 1805 times.
|
58894 | if (search_if_impossible) { |
| 9658 |
2/2✓ Branch 0 taken 412 times.
✓ Branch 1 taken 56677 times.
|
57089 | if (tab->range_scan()) { |
| 9659 | 412 | destroy(tab->range_scan()); | |
| 9660 | 412 | tab->set_type(JT_ALL); | |
| 9661 | } | ||
| 9662 | AccessPath *range_scan; | ||
| 9663 | MEM_ROOT temp_mem_root(key_memory_test_quick_select_exec, | ||
| 9664 | 57089 | thd->variables.range_alloc_block_size); | |
| 9665 | 57089 | search_if_impossible = | |
| 9666 | 114178 | test_quick_select( | |
| 9667 | thd, thd->mem_root, &temp_mem_root, usable_keys, | ||
| 9668 |
1/2✓ Branch 0 taken 57089 times.
✗ Branch 1 not taken.
|
57089 | used_tables & ~tab->table_ref->map(), 0, |
| 9669 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 57089 times.
|
57089 | join->calc_found_rows |
| 9670 | ? HA_POS_ERROR | ||
| 9671 | 57089 | : join->query_expression()->select_limit_cnt, | |
| 9672 | false, // don't force quick range | ||
| 9673 | interesting_order, tab->table(), | ||
| 9674 | 57089 | tab->skip_records_in_range(), tab->condition(), | |
| 9675 | 57089 | &tab->needed_reg, tab->table()->force_index, | |
| 9676 | 57089 | join->query_block, &range_scan) < 0; | |
| 9677 | 57089 | tab->set_range_scan(range_scan); | |
| 9678 | 57089 | } | |
| 9679 | 58894 | tab->set_condition(orig_cond); | |
| 9680 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 58891 times.
|
58894 | if (search_if_impossible) { |
| 9681 | /* | ||
| 9682 | Before reporting "Impossible WHERE" for the whole query | ||
| 9683 | we have to check isn't it only "impossible ON" instead | ||
| 9684 | */ | ||
| 9685 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (!tab->join_cond()) |
| 9686 | 3 | return true; // No ON, so it's really "impossible WHERE" | |
| 9687 | ✗ | Opt_trace_object trace_without_on(trace, "without_ON_clause"); | |
| 9688 | ✗ | if (tab->range_scan()) { | |
| 9689 | ✗ | destroy(tab->range_scan()); | |
| 9690 | ✗ | tab->set_type(JT_ALL); | |
| 9691 | } | ||
| 9692 | AccessPath *range_scan; | ||
| 9693 | MEM_ROOT temp_mem_root(key_memory_test_quick_select_exec, | ||
| 9694 | ✗ | thd->variables.range_alloc_block_size); | |
| 9695 | const bool impossible_where = | ||
| 9696 | ✗ | test_quick_select( | |
| 9697 | ✗ | thd, thd->mem_root, &temp_mem_root, tab->keys(), | |
| 9698 | ✗ | used_tables & ~tab->table_ref->map(), 0, | |
| 9699 | ✗ | join->calc_found_rows | |
| 9700 | ? HA_POS_ERROR | ||
| 9701 | ✗ | : join->query_expression()->select_limit_cnt, | |
| 9702 | false, // don't force quick range | ||
| 9703 | ORDER_NOT_RELEVANT, tab->table(), | ||
| 9704 | ✗ | tab->skip_records_in_range(), tab->condition(), | |
| 9705 | ✗ | &tab->needed_reg, tab->table()->force_index, | |
| 9706 | ✗ | join->query_block, &range_scan) < 0; | |
| 9707 | ✗ | tab->set_range_scan(range_scan); | |
| 9708 | ✗ | if (impossible_where) return true; // Impossible WHERE | |
| 9709 | } | ||
| 9710 | |||
| 9711 | /* | ||
| 9712 | Access method changed. This is after deciding join order | ||
| 9713 | and access method for all other tables so the info | ||
| 9714 | updated below will not have any effect on the execution | ||
| 9715 | plan. | ||
| 9716 | */ | ||
| 9717 |
2/2✓ Branch 0 taken 1764 times.
✓ Branch 1 taken 57127 times.
|
58891 | if (tab->range_scan()) |
| 9718 |
1/2✓ Branch 0 taken 1764 times.
✗ Branch 1 not taken.
|
1764 | tab->set_type(calc_join_type(tab->range_scan())); |
| 9719 | |||
| 9720 |
4/4✓ Branch 0 taken 58891 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 58891 times.
✓ Branch 3 taken 3 times.
|
58897 | } // end of "if (recheck_reason != DONT_RECHECK)" |
| 9721 | |||
| 9722 |
4/4✓ Branch 0 taken 1359488 times.
✓ Branch 1 taken 22763 times.
✓ Branch 2 taken 23374 times.
✓ Branch 3 taken 1358877 times.
|
2741739 | if (!tab->table()->quick_keys.is_subset(tab->checked_keys) || |
| 9723 |
2/2✓ Branch 0 taken 611 times.
✓ Branch 1 taken 1358877 times.
|
1359488 | !tab->needed_reg.is_subset(tab->checked_keys)) { |
| 9724 | 23374 | tab->keys().merge(tab->table()->quick_keys); | |
| 9725 | 23374 | tab->keys().merge(tab->needed_reg); | |
| 9726 | |||
| 9727 | /* | ||
| 9728 | The logic below for assigning tab->use_quick is strange. | ||
| 9729 | It bases the decision of which access method to use | ||
| 9730 | (dynamic range, range, scan) based on seemingly | ||
| 9731 | unrelated information like the presence of another index | ||
| 9732 | with too bad selectivity to be used. | ||
| 9733 | |||
| 9734 | Consider the following scenario: | ||
| 9735 | |||
| 9736 | The join optimizer has decided to use join order | ||
| 9737 | (t1,t2), and 'tab' is currently t2. Further, assume that | ||
| 9738 | there is a join condition between t1 and t2 using some | ||
| 9739 | range operator (e.g. "t1.x < t2.y"). | ||
| 9740 | |||
| 9741 | It has been decided that a table scan is best for t2. | ||
| 9742 | make_join_query_block() then reran the range optimizer a few | ||
| 9743 | lines up because there is an index 't2.good_idx' | ||
| 9744 | covering the t2.y column. If 'good_idx' is the only | ||
| 9745 | index in t2, the decision below will be to use dynamic | ||
| 9746 | range. However, if t2 also has another index 't2.other' | ||
| 9747 | which the range access method can be used on but | ||
| 9748 | selectivity is bad (#rows estimate is high), then table | ||
| 9749 | scan is chosen instead. | ||
| 9750 | |||
| 9751 | Thus, the choice of DYNAMIC RANGE vs SCAN depends on the | ||
| 9752 | presence of an index that has so bad selectivity that it | ||
| 9753 | will not be used anyway. | ||
| 9754 | */ | ||
| 9755 |
6/6✓ Branch 0 taken 629 times.
✓ Branch 1 taken 22745 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 611 times.
✓ Branch 4 taken 611 times.
✓ Branch 5 taken 22763 times.
|
24021 | if (!tab->needed_reg.is_clear_all() && |
| 9756 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
|
647 | (tab->table()->quick_keys.is_clear_all() || |
| 9757 | 18 | (tab->range_scan() && | |
| 9758 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | (tab->range_scan()->num_output_rows >= 100.0)))) { |
| 9759 | 611 | tab->use_quick = QS_DYNAMIC_RANGE; | |
| 9760 | 611 | tab->set_type(JT_ALL); | |
| 9761 | } else | ||
| 9762 | 22763 | tab->use_quick = QS_RANGE; | |
| 9763 | } | ||
| 9764 | |||
| 9765 |
6/6✓ Branch 0 taken 1381737 times.
✓ Branch 1 taken 514 times.
✓ Branch 2 taken 401 times.
✓ Branch 3 taken 1381336 times.
✓ Branch 4 taken 915 times.
✓ Branch 5 taken 1381336 times.
|
2763988 | if (tab->type() != orig_join_type || |
| 9766 | 1381737 | tab->range_scan() != orig_range_scan) // Access method changed | |
| 9767 | 915 | tab->position()->filter_effect = COND_FILTER_STALE; | |
| 9768 | } | ||
| 9769 | } | ||
| 9770 | |||
| 9771 |
2/4✓ Branch 0 taken 3779735 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3779735 times.
|
3779784 | if (join->attach_join_conditions(i)) return true; |
| 9772 | } | ||
| 9773 |
1/2✓ Branch 0 taken 1814608 times.
✗ Branch 1 not taken.
|
1814715 | trace_attached_comp.end(); |
| 9774 | |||
| 9775 | /* | ||
| 9776 | In outer joins the loop above, in iteration for table #i, may push | ||
| 9777 | conditions to a table before #i. Thus, the processing below has to be in | ||
| 9778 | a separate loop: | ||
| 9779 | */ | ||
| 9780 | Opt_trace_array trace_attached_summary(trace, | ||
| 9781 |
1/2✓ Branch 0 taken 1814618 times.
✗ Branch 1 not taken.
|
1814608 | "attached_conditions_summary"); |
| 9782 |
2/2✓ Branch 0 taken 6165142 times.
✓ Branch 1 taken 1814716 times.
|
7979858 | for (uint i = join->const_tables; i < join->tables; i++) { |
| 9783 | 6165142 | JOIN_TAB *const tab = join->best_ref[i]; | |
| 9784 |
2/2✓ Branch 0 taken 2385460 times.
✓ Branch 1 taken 3779772 times.
|
6165142 | if (!tab->table()) continue; |
| 9785 | 3779772 | Item *const tab_cond = tab->condition(); | |
| 9786 |
1/2✓ Branch 0 taken 3779796 times.
✗ Branch 1 not taken.
|
3779801 | Opt_trace_object trace_one_table(trace); |
| 9787 |
2/4✓ Branch 0 taken 3779794 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3779791 times.
✗ Branch 3 not taken.
|
3779796 | trace_one_table.add_utf8_table(tab->table_ref).add("attached", tab_cond); |
| 9788 |
6/6✓ Branch 0 taken 2687776 times.
✓ Branch 1 taken 1092015 times.
✓ Branch 2 taken 12887 times.
✓ Branch 3 taken 2674896 times.
✓ Branch 4 taken 12887 times.
✓ Branch 5 taken 3766911 times.
|
3779791 | if (tab_cond && tab_cond->has_subquery()) // traverse only if needed |
| 9789 | { | ||
| 9790 | /* | ||
| 9791 | Why we pass walk_subquery=false: imagine | ||
| 9792 | WHERE t1.col IN (SELECT * FROM t2 | ||
| 9793 | WHERE t2.col IN (SELECT * FROM t3) | ||
| 9794 | and tab==t1. The grandchild subquery (SELECT * FROM t3) should not | ||
| 9795 | be marked as "in condition of t1" but as "in condition of t2", for | ||
| 9796 | correct calculation of the number of its executions. | ||
| 9797 | */ | ||
| 9798 | 12887 | std::pair<Query_block *, int> pair_object(join->query_block, i); | |
| 9799 |
1/2✓ Branch 0 taken 12887 times.
✗ Branch 1 not taken.
|
12887 | tab_cond->walk(&Item::inform_item_in_cond_of_tab, enum_walk::POSTFIX, |
| 9800 | pointer_cast<uchar *>(&pair_object)); | ||
| 9801 | } | ||
| 9802 | 3779798 | } | |
| 9803 |
6/6✓ Branch 0 taken 1814613 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 1814625 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 1814624 times.
✓ Branch 5 taken 2 times.
|
1814736 | } |
| 9804 | 1814624 | return false; | |
| 9805 | 1816634 | } | |
| 9806 | |||
| 9807 | /** | ||
| 9808 | Remove the following expressions from ORDER BY and GROUP BY: | ||
| 9809 | Constant expressions @n | ||
| 9810 | Expression that only uses tables that are of type EQ_REF and the reference | ||
| 9811 | is in the ORDER list or if all refereed tables are of the above type. | ||
| 9812 | |||
| 9813 | In the following, the X field can be removed: | ||
| 9814 | @code | ||
| 9815 | SELECT * FROM t1,t2 WHERE t1.a=t2.a ORDER BY t1.a,t2.X | ||
| 9816 | SELECT * FROM t1,t2,t3 WHERE t1.a=t2.a AND t2.b=t3.b ORDER BY t1.a,t3.X | ||
| 9817 | @endcode | ||
| 9818 | |||
| 9819 | These can't be optimized: | ||
| 9820 | @code | ||
| 9821 | SELECT * FROM t1,t2 WHERE t1.a=t2.a ORDER BY t2.X,t1.a | ||
| 9822 | SELECT * FROM t1,t2 WHERE t1.a=t2.a AND t1.b=t2.b ORDER BY t1.a,t2.c | ||
| 9823 | SELECT * FROM t1,t2 WHERE t1.a=t2.a ORDER BY t2.b,t1.a | ||
| 9824 | @endcode | ||
| 9825 | |||
| 9826 | @param join join object | ||
| 9827 | @param start_order clause being analyzed (ORDER BY, GROUP BY...) | ||
| 9828 | @param tab table | ||
| 9829 | @param cached_eq_ref_tables bitmap: bit Z is set if the table of map Z | ||
| 9830 | was already the subject of an eq_ref_table() call for the same clause; then | ||
| 9831 | the return value of this previous call can be found at bit Z of | ||
| 9832 | 'eq_ref_tables' | ||
| 9833 | @param eq_ref_tables see above. | ||
| 9834 | */ | ||
| 9835 | |||
| 9836 | 376218 | static bool eq_ref_table(JOIN *join, ORDER *start_order, JOIN_TAB *tab, | |
| 9837 | table_map *cached_eq_ref_tables, | ||
| 9838 | table_map *eq_ref_tables) { | ||
| 9839 | /* We can skip const tables only if not an outer table */ | ||
| 9840 |
6/6✓ Branch 0 taken 10 times.
✓ Branch 1 taken 376208 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 376217 times.
|
376218 | if (tab->type() == JT_CONST && tab->first_inner() == NO_PLAN_IDX) return true; |
| 9841 |
6/6✓ Branch 0 taken 104936 times.
✓ Branch 1 taken 271281 times.
✓ Branch 2 taken 235 times.
✓ Branch 3 taken 104701 times.
✓ Branch 4 taken 271516 times.
✓ Branch 5 taken 104701 times.
|
376217 | if (tab->type() != JT_EQ_REF || tab->table()->is_nullable()) return false; |
| 9842 | |||
| 9843 | 104701 | const table_map map = tab->table_ref->map(); | |
| 9844 | 104701 | uint found = 0; | |
| 9845 | |||
| 9846 | 104755 | for (Item **ref_item = tab->ref().items, | |
| 9847 | 104701 | **end = ref_item + tab->ref().key_parts; | |
| 9848 |
2/2✓ Branch 0 taken 104702 times.
✓ Branch 1 taken 53 times.
|
104755 | ref_item != end; ref_item++) { |
| 9849 |
1/2✓ Branch 0 taken 104702 times.
✗ Branch 1 not taken.
|
104702 | if (!(*ref_item)->const_item()) { // Not a const ref |
| 9850 | ORDER *order; | ||
| 9851 |
2/2✓ Branch 0 taken 290797 times.
✓ Branch 1 taken 104651 times.
|
395448 | for (order = start_order; order; order = order->next) { |
| 9852 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 290746 times.
|
290797 | if ((*ref_item)->eq(order->item[0], false)) break; |
| 9853 | } | ||
| 9854 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 104651 times.
|
104702 | if (order) { |
| 9855 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 1 times.
|
51 | if (!(order->used & map)) { |
| 9856 | 50 | found++; | |
| 9857 | 50 | order->used |= map; | |
| 9858 | } | ||
| 9859 | 51 | continue; // Used in ORDER BY | |
| 9860 | } | ||
| 9861 |
2/2✓ Branch 0 taken 104648 times.
✓ Branch 1 taken 3 times.
|
104651 | if (!only_eq_ref_tables(join, start_order, (*ref_item)->used_tables(), |
| 9862 | cached_eq_ref_tables, eq_ref_tables)) | ||
| 9863 | 104648 | return false; | |
| 9864 | } | ||
| 9865 | } | ||
| 9866 | /* Check that there was no reference to table before sort order */ | ||
| 9867 |
3/4✓ Branch 0 taken 86 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 86 times.
✗ Branch 3 not taken.
|
96 | for (; found && start_order; start_order = start_order->next) { |
| 9868 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 79 times.
|
86 | if (start_order->used & map) { |
| 9869 | 7 | found--; | |
| 9870 | 7 | continue; | |
| 9871 | } | ||
| 9872 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 36 times.
|
79 | if (start_order->depend_map & map) return false; |
| 9873 | } | ||
| 9874 | 10 | return true; | |
| 9875 | } | ||
| 9876 | |||
| 9877 | /// @see eq_ref_table() | ||
| 9878 | 486003 | static bool only_eq_ref_tables(JOIN *join, ORDER *order, table_map tables, | |
| 9879 | table_map *cached_eq_ref_tables, | ||
| 9880 | table_map *eq_ref_tables) { | ||
| 9881 | 486003 | tables &= ~PSEUDO_TABLE_BITS; | |
| 9882 |
2/2✓ Branch 0 taken 667059 times.
✓ Branch 1 taken 11 times.
|
667070 | for (JOIN_TAB **tab = join->map2table; tables; tab++, tables >>= 1) { |
| 9883 |
2/2✓ Branch 0 taken 486003 times.
✓ Branch 1 taken 181056 times.
|
667059 | if (tables & 1) { |
| 9884 | 486003 | const table_map map = (*tab)->table_ref->map(); | |
| 9885 | bool is_eq_ref; | ||
| 9886 |
2/2✓ Branch 0 taken 109785 times.
✓ Branch 1 taken 376218 times.
|
486003 | if (*cached_eq_ref_tables & map) // then there exists a cached bit |
| 9887 | 109785 | is_eq_ref = *eq_ref_tables & map; | |
| 9888 | else { | ||
| 9889 | 376218 | is_eq_ref = eq_ref_table(join, order, *tab, cached_eq_ref_tables, | |
| 9890 | eq_ref_tables); | ||
| 9891 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 376207 times.
|
376218 | if (is_eq_ref) |
| 9892 | 11 | *eq_ref_tables |= map; | |
| 9893 | else | ||
| 9894 | 376207 | *eq_ref_tables &= ~map; | |
| 9895 | 376218 | *cached_eq_ref_tables |= map; // now there exists a cached bit | |
| 9896 | } | ||
| 9897 |
2/2✓ Branch 0 taken 485992 times.
✓ Branch 1 taken 11 times.
|
486003 | if (!is_eq_ref) return false; |
| 9898 | } | ||
| 9899 | } | ||
| 9900 | 11 | return true; | |
| 9901 | } | ||
| 9902 | |||
| 9903 | /** | ||
| 9904 | Check if an expression in ORDER BY or GROUP BY is a duplicate of a | ||
| 9905 | preceding expression. | ||
| 9906 | |||
| 9907 | @param first_order the first expression in the ORDER BY or | ||
| 9908 | GROUP BY clause | ||
| 9909 | @param possible_dup the expression that might be a duplicate of | ||
| 9910 | another expression preceding it the ORDER BY | ||
| 9911 | or GROUP BY clause | ||
| 9912 | |||
| 9913 | @returns true if possible_dup is a duplicate, false otherwise | ||
| 9914 | */ | ||
| 9915 | 892910 | static bool duplicate_order(const ORDER *first_order, | |
| 9916 | const ORDER *possible_dup) { | ||
| 9917 | const ORDER *order; | ||
| 9918 |
1/2✓ Branch 0 taken 2468077 times.
✗ Branch 1 not taken.
|
2468077 | for (order = first_order; order; order = order->next) { |
| 9919 |
2/2✓ Branch 0 taken 892765 times.
✓ Branch 1 taken 1575312 times.
|
2468077 | if (order == possible_dup) { |
| 9920 | // all expressions preceding possible_dup have been checked. | ||
| 9921 | 892765 | return false; | |
| 9922 | } else { | ||
| 9923 | 1575312 | const Item *it1 = order->item[0]->real_item(); | |
| 9924 | 1575312 | const Item *it2 = possible_dup->item[0]->real_item(); | |
| 9925 | |||
| 9926 |
2/2✓ Branch 0 taken 145 times.
✓ Branch 1 taken 1575167 times.
|
1575312 | if (it1->eq(it2, false)) return true; |
| 9927 | } | ||
| 9928 | } | ||
| 9929 | ✗ | return false; | |
| 9930 | } | ||
| 9931 | |||
| 9932 | /** | ||
| 9933 | Remove all constants and check if ORDER only contains simple | ||
| 9934 | expressions. | ||
| 9935 | |||
| 9936 | simple_order is set to true if sort_order only uses fields from head table | ||
| 9937 | and the head table is not a LEFT JOIN table. | ||
| 9938 | |||
| 9939 | @param first_order List of GROUP BY or ORDER BY sub-clauses. | ||
| 9940 | @param cond WHERE condition. | ||
| 9941 | @param change If true, remove sub-clauses that need not be evaluated. | ||
| 9942 | If this is not set, then only simple_order is calculated. | ||
| 9943 | @param[out] simple_order Set to true if we are only using simple expressions. | ||
| 9944 | @param group_by True if first_order represents a grouping operation. | ||
| 9945 | |||
| 9946 | @returns new sort order, after const elimination (when change is true). | ||
| 9947 | */ | ||
| 9948 | |||
| 9949 | 3628998 | ORDER *JOIN::remove_const(ORDER *first_order, Item *cond, bool change, | |
| 9950 | bool *simple_order, bool group_by) { | ||
| 9951 |
1/2✓ Branch 0 taken 3629209 times.
✗ Branch 1 not taken.
|
3628998 | DBUG_TRACE; |
| 9952 | |||
| 9953 |
3/6✓ Branch 0 taken 3629213 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3629217 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3629217 times.
✗ Branch 5 not taken.
|
3629209 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 9954 | |||
| 9955 |
2/2✓ Branch 0 taken 164752 times.
✓ Branch 1 taken 3464464 times.
|
3629213 | if (plan_is_const()) |
| 9956 |
2/2✓ Branch 0 taken 164744 times.
✓ Branch 1 taken 8 times.
|
164752 | return change ? nullptr : first_order; // No need to sort |
| 9957 | |||
| 9958 | 3464464 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 9959 |
1/2✓ Branch 0 taken 3464457 times.
✗ Branch 1 not taken.
|
3464464 | Opt_trace_disable_I_S trace_disabled(trace, first_order == nullptr); |
| 9960 | Opt_trace_object trace_simpl( | ||
| 9961 |
3/4✓ Branch 0 taken 1732216 times.
✓ Branch 1 taken 1732241 times.
✓ Branch 2 taken 3464456 times.
✗ Branch 3 not taken.
|
3464457 | trace, group_by ? "simplifying_group_by" : "simplifying_order_by"); |
| 9962 |
2/2✓ Branch 0 taken 5256 times.
✓ Branch 1 taken 3459193 times.
|
3464456 | if (trace->is_started()) { |
| 9963 | 5256 | String str; | |
| 9964 | 5256 | Query_block::print_order( | |
| 9965 |
1/2✓ Branch 0 taken 5256 times.
✗ Branch 1 not taken.
|
5256 | thd, &str, first_order, |
| 9966 | enum_query_type(QT_TO_SYSTEM_CHARSET | QT_SHOW_SELECT_NUMBER | | ||
| 9967 | QT_NO_DEFAULT_DB)); | ||
| 9968 |
1/2✓ Branch 0 taken 5256 times.
✗ Branch 1 not taken.
|
5256 | trace_simpl.add_utf8("original_clause", str.ptr(), str.length()); |
| 9969 | 5256 | } | |
| 9970 |
1/2✓ Branch 0 taken 3464428 times.
✗ Branch 1 not taken.
|
3464449 | Opt_trace_array trace_each_item(trace, "items"); |
| 9971 | |||
| 9972 | 3464428 | JOIN_TAB *const first_tab = best_ref[const_tables]; | |
| 9973 | 3464428 | table_map first_table = first_tab->table_ref->map(); | |
| 9974 | 3464450 | table_map not_const_tables = ~const_table_map; | |
| 9975 | table_map ref; | ||
| 9976 | // Caches to avoid repeating eq_ref_table() calls, @see eq_ref_table() | ||
| 9977 | 3464450 | table_map eq_ref_tables = 0, cached_eq_ref_tables = 0; | |
| 9978 | |||
| 9979 | 3464450 | ORDER **prev_ptr = &first_order; | |
| 9980 | 3464450 | *simple_order = !first_tab->join_cond(); | |
| 9981 | |||
| 9982 | // De-optimization in conjunction with window functions | ||
| 9983 |
4/4✓ Branch 0 taken 1732214 times.
✓ Branch 1 taken 1732230 times.
✓ Branch 2 taken 1889 times.
✓ Branch 3 taken 1730325 times.
|
3464444 | if (group_by && m_windows.elements > 0) *simple_order = false; |
| 9984 | |||
| 9985 |
1/2✓ Branch 0 taken 3464464 times.
✗ Branch 1 not taken.
|
3464444 | update_depend_map(first_order); |
| 9986 | |||
| 9987 |
2/2✓ Branch 0 taken 893923 times.
✓ Branch 1 taken 3464464 times.
|
4358387 | for (ORDER *order = first_order; order; order = order->next) { |
| 9988 |
1/2✓ Branch 0 taken 893923 times.
✗ Branch 1 not taken.
|
893923 | Opt_trace_object trace_one_item(trace); |
| 9989 |
1/2✓ Branch 0 taken 893923 times.
✗ Branch 1 not taken.
|
893923 | trace_one_item.add("item", order->item[0]); |
| 9990 |
1/2✓ Branch 0 taken 893923 times.
✗ Branch 1 not taken.
|
893923 | table_map order_tables = order->item[0]->used_tables(); |
| 9991 | |||
| 9992 |
6/6✓ Branch 0 taken 893574 times.
✓ Branch 1 taken 349 times.
✓ Branch 2 taken 893485 times.
✓ Branch 3 taken 89 times.
✓ Branch 4 taken 473 times.
✓ Branch 5 taken 893450 times.
|
1787408 | if (order->item[0]->has_aggregation() || order->item[0]->has_wf() || |
| 9993 | /* | ||
| 9994 | If the outer table of an outer join is const (either by itself or | ||
| 9995 | after applying WHERE condition), grouping on a field from such a | ||
| 9996 | table will be optimized away and filesort without temporary table | ||
| 9997 | will be used unless we prevent that now. Filesort is not fit to | ||
| 9998 | handle joins and the join condition is not applied. We can't detect | ||
| 9999 | the case without an expensive test, however, so we force temporary | ||
| 10000 | table for all queries containing more than one table, ROLLUP, and an | ||
| 10001 | outer join. | ||
| 10002 | */ | ||
| 10003 |
4/4✓ Branch 0 taken 428070 times.
✓ Branch 1 taken 465415 times.
✓ Branch 2 taken 74 times.
✓ Branch 3 taken 427996 times.
|
893485 | (primary_tables > 1 && rollup_state == RollupState::INITED && |
| 10004 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 39 times.
|
74 | query_block->outer_join)) { |
| 10005 | 473 | *simple_order = false; // Must use a temporary table to sort | |
| 10006 |
4/4✓ Branch 0 taken 542 times.
✓ Branch 1 taken 892908 times.
✓ Branch 2 taken 540 times.
✓ Branch 3 taken 892910 times.
|
893992 | } else if ((order_tables & not_const_tables) == 0 && |
| 10007 |
3/4✓ Branch 0 taken 542 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 540 times.
✓ Branch 3 taken 2 times.
|
542 | evaluate_during_optimization(order->item[0], query_block)) { |
| 10008 |
2/2✓ Branch 0 taken 158 times.
✓ Branch 1 taken 382 times.
|
540 | if (order->item[0]->has_subquery()) { |
| 10009 |
2/2✓ Branch 0 taken 138 times.
✓ Branch 1 taken 20 times.
|
158 | if (!thd->lex->is_explain()) { |
| 10010 |
1/2✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
|
138 | Opt_trace_array trace_subselect(trace, "subselect_evaluation"); |
| 10011 | 138 | String str; | |
| 10012 |
1/2✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
|
138 | order->item[0]->val_str(&str); |
| 10013 | 138 | } | |
| 10014 |
1/2✓ Branch 0 taken 158 times.
✗ Branch 1 not taken.
|
158 | order->item[0]->mark_subqueries_optimized_away(); |
| 10015 | } | ||
| 10016 |
1/2✓ Branch 0 taken 540 times.
✗ Branch 1 not taken.
|
540 | trace_one_item.add("uses_only_constant_tables", true); |
| 10017 | 540 | continue; // skip const item | |
| 10018 |
3/4✓ Branch 0 taken 892910 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 145 times.
✓ Branch 3 taken 892765 times.
|
893450 | } else if (duplicate_order(first_order, order)) { |
| 10019 | /* | ||
| 10020 | If 'order' is a duplicate of an expression earlier in the | ||
| 10021 | ORDER/GROUP BY sequence, it can be removed from the ORDER BY | ||
| 10022 | or GROUP BY clause. | ||
| 10023 | */ | ||
| 10024 |
1/2✓ Branch 0 taken 145 times.
✗ Branch 1 not taken.
|
145 | trace_one_item.add("duplicate_item", true); |
| 10025 | 145 | continue; | |
| 10026 |
6/6✓ Branch 0 taken 859688 times.
✓ Branch 1 taken 33077 times.
✓ Branch 2 taken 58 times.
✓ Branch 3 taken 859630 times.
✓ Branch 4 taken 58 times.
✓ Branch 5 taken 892707 times.
|
892765 | } else if (order->in_field_list && order->item[0]->has_subquery()) { |
| 10027 | /* | ||
| 10028 | If the order item is a subquery that is also in the field | ||
| 10029 | list, a temp table should be used to avoid evaluating the | ||
| 10030 | subquery for each row both when a) creating a sort index and | ||
| 10031 | b) getting the value. | ||
| 10032 | Example: "SELECT (SELECT ... ) as a ... GROUP BY a;" | ||
| 10033 | */ | ||
| 10034 | 58 | *simple_order = false; | |
| 10035 |
2/2✓ Branch 0 taken 341 times.
✓ Branch 1 taken 892366 times.
|
892707 | } else if (order_tables & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT)) { |
| 10036 | 341 | *simple_order = false; | |
| 10037 | } else { | ||
| 10038 |
7/8✓ Branch 0 taken 548389 times.
✓ Branch 1 taken 343977 times.
✓ Branch 2 taken 548389 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15446 times.
✓ Branch 5 taken 532943 times.
✓ Branch 6 taken 15446 times.
✓ Branch 7 taken 876920 times.
|
892366 | if (cond != nullptr && check_field_is_const(cond, order->item[0])) { |
| 10039 |
1/2✓ Branch 0 taken 15446 times.
✗ Branch 1 not taken.
|
15446 | trace_one_item.add("equals_constant_in_where", true); |
| 10040 | 15446 | continue; | |
| 10041 | } | ||
| 10042 |
2/2✓ Branch 0 taken 381526 times.
✓ Branch 1 taken 495394 times.
|
876920 | if ((ref = order_tables & (not_const_tables ^ first_table))) { |
| 10043 |
4/4✓ Branch 0 taken 381352 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 381518 times.
|
762878 | if (!(order_tables & first_table) && |
| 10044 |
3/4✓ Branch 0 taken 381352 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 381344 times.
|
381352 | only_eq_ref_tables(this, first_order, ref, &cached_eq_ref_tables, |
| 10045 | &eq_ref_tables)) { | ||
| 10046 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | trace_one_item.add("eq_ref_to_preceding_items", true); |
| 10047 | 8 | continue; | |
| 10048 | } | ||
| 10049 | 381518 | *simple_order = false; // Must do a temp table to sort | |
| 10050 | } | ||
| 10051 | } | ||
| 10052 |
2/2✓ Branch 0 taken 877195 times.
✓ Branch 1 taken 589 times.
|
877784 | if (change) *prev_ptr = order; // use this entry |
| 10053 | 877784 | prev_ptr = &order->next; | |
| 10054 |
2/2✓ Branch 0 taken 877784 times.
✓ Branch 1 taken 16139 times.
|
893923 | } |
| 10055 |
2/2✓ Branch 0 taken 3463623 times.
✓ Branch 1 taken 841 times.
|
3464464 | if (change) *prev_ptr = nullptr; |
| 10056 |
2/2✓ Branch 0 taken 2903486 times.
✓ Branch 1 taken 560978 times.
|
3464464 | if (prev_ptr == &first_order) // Nothing to sort/group |
| 10057 | 2903486 | *simple_order = true; | |
| 10058 |
5/8✓ Branch 0 taken 3464427 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3464451 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 52 times.
✓ Branch 5 taken 3464399 times.
✓ Branch 6 taken 52 times.
✗ Branch 7 not taken.
|
3464464 | DBUG_PRINT("exit", ("simple_order: %d", (int)*simple_order)); |
| 10059 | |||
| 10060 |
1/2✓ Branch 0 taken 3464431 times.
✗ Branch 1 not taken.
|
3464451 | trace_each_item.end(); |
| 10061 |
1/2✓ Branch 0 taken 3464439 times.
✗ Branch 1 not taken.
|
3464431 | trace_simpl.add("resulting_clause_is_simple", *simple_order); |
| 10062 |
6/6✓ Branch 0 taken 5256 times.
✓ Branch 1 taken 3459186 times.
✓ Branch 2 taken 5250 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 5250 times.
✓ Branch 5 taken 3459192 times.
|
3464439 | if (trace->is_started() && change) { |
| 10063 | 5250 | String str; | |
| 10064 | 5250 | Query_block::print_order( | |
| 10065 |
1/2✓ Branch 0 taken 5250 times.
✗ Branch 1 not taken.
|
5250 | thd, &str, first_order, |
| 10066 | enum_query_type(QT_TO_SYSTEM_CHARSET | QT_SHOW_SELECT_NUMBER | | ||
| 10067 | QT_NO_DEFAULT_DB)); | ||
| 10068 |
1/2✓ Branch 0 taken 5250 times.
✗ Branch 1 not taken.
|
5250 | trace_simpl.add_utf8("resulting_clause", str.ptr(), str.length()); |
| 10069 | 5250 | } | |
| 10070 | |||
| 10071 | 3464442 | return first_order; | |
| 10072 | 3629194 | } | |
| 10073 | |||
| 10074 | /** | ||
| 10075 | Optimize conditions by | ||
| 10076 | |||
| 10077 | a) applying transitivity to build multiple equality predicates | ||
| 10078 | (MEP): if x=y and y=z the MEP x=y=z is built. | ||
| 10079 | b) apply constants where possible. If the value of x is known to be | ||
| 10080 | 42, x is replaced with a constant of value 42. By transitivity, this | ||
| 10081 | also applies to MEPs, so the MEP in a) will become 42=x=y=z. | ||
| 10082 | c) remove conditions that are always false or always true | ||
| 10083 | |||
| 10084 | @param thd Thread handler | ||
| 10085 | @param[in,out] cond WHERE or HAVING condition to optimize | ||
| 10086 | @param[out] cond_equal The built multiple equalities | ||
| 10087 | @param join_list list of join operations with join conditions | ||
| 10088 | = NULL: Called for HAVING condition | ||
| 10089 | @param[out] cond_value Not changed if cond was empty | ||
| 10090 | COND_TRUE if cond is always true | ||
| 10091 | COND_FALSE if cond is impossible | ||
| 10092 | COND_OK otherwise | ||
| 10093 | |||
| 10094 | |||
| 10095 | @returns false if success, true if error | ||
| 10096 | */ | ||
| 10097 | |||
| 10098 | 1521963 | bool optimize_cond(THD *thd, Item **cond, COND_EQUAL **cond_equal, | |
| 10099 | mem_root_deque<TABLE_LIST *> *join_list, | ||
| 10100 | Item::cond_result *cond_value) { | ||
| 10101 |
1/2✓ Branch 0 taken 1522119 times.
✗ Branch 1 not taken.
|
1521963 | DBUG_TRACE; |
| 10102 | 1522119 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 10103 | |||
| 10104 |
1/2✓ Branch 0 taken 1522057 times.
✗ Branch 1 not taken.
|
1522119 | Opt_trace_object trace_wrapper(trace); |
| 10105 |
1/2✓ Branch 0 taken 1522104 times.
✗ Branch 1 not taken.
|
1522057 | Opt_trace_object trace_cond(trace, "condition_processing"); |
| 10106 |
3/4✓ Branch 0 taken 1511859 times.
✓ Branch 1 taken 10245 times.
✓ Branch 2 taken 1522071 times.
✗ Branch 3 not taken.
|
1522104 | trace_cond.add_alnum("condition", join_list ? "WHERE" : "HAVING"); |
| 10107 |
1/2✓ Branch 0 taken 1522103 times.
✗ Branch 1 not taken.
|
1522071 | trace_cond.add("original_condition", *cond); |
| 10108 |
1/2✓ Branch 0 taken 1522093 times.
✗ Branch 1 not taken.
|
1522103 | Opt_trace_array trace_steps(trace, "steps"); |
| 10109 | |||
| 10110 | /* | ||
| 10111 | Enter this function | ||
| 10112 | a) For a WHERE condition or a query having outer join. | ||
| 10113 | b) For a HAVING condition. | ||
| 10114 | */ | ||
| 10115 |
3/4✓ Branch 0 taken 5301 times.
✓ Branch 1 taken 1516792 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5301 times.
|
1522093 | assert(*cond || join_list); |
| 10116 | |||
| 10117 | /* | ||
| 10118 | Build all multiple equality predicates and eliminate equality | ||
| 10119 | predicates that can be inferred from these multiple equalities. | ||
| 10120 | For each reference of a field included into a multiple equality | ||
| 10121 | that occurs in a function set a pointer to the multiple equality | ||
| 10122 | predicate. Substitute a constant instead of this field if the | ||
| 10123 | multiple equality contains a constant. | ||
| 10124 | This is performed for the WHERE condition and any join conditions, but | ||
| 10125 | not for the HAVING condition. | ||
| 10126 | */ | ||
| 10127 |
2/2✓ Branch 0 taken 1511854 times.
✓ Branch 1 taken 10239 times.
|
1522093 | if (join_list) { |
| 10128 |
1/2✓ Branch 0 taken 1511863 times.
✗ Branch 1 not taken.
|
1511854 | Opt_trace_object step_wrapper(trace); |
| 10129 |
1/2✓ Branch 0 taken 1511863 times.
✗ Branch 1 not taken.
|
1511863 | step_wrapper.add_alnum("transformation", "equality_propagation"); |
| 10130 | { | ||
| 10131 | Opt_trace_disable_I_S disable_trace_wrapper( | ||
| 10132 |
5/6✓ Branch 0 taken 1506500 times.
✓ Branch 1 taken 5363 times.
✓ Branch 2 taken 1480432 times.
✓ Branch 3 taken 26057 times.
✓ Branch 4 taken 1511763 times.
✗ Branch 5 not taken.
|
1511863 | trace, !(*cond && (*cond)->has_subquery())); |
| 10133 |
1/2✓ Branch 0 taken 1511839 times.
✗ Branch 1 not taken.
|
1511763 | Opt_trace_array trace_subselect(trace, "subselect_evaluation"); |
| 10134 |
3/4✓ Branch 0 taken 1511811 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1511810 times.
|
1511839 | if (build_equal_items(thd, *cond, cond, nullptr, true, join_list, |
| 10135 | cond_equal)) | ||
| 10136 | 1 | return true; | |
| 10137 |
2/4✓ Branch 0 taken 1511759 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1511785 times.
✗ Branch 3 not taken.
|
1511811 | } |
| 10138 |
1/2✓ Branch 0 taken 1511791 times.
✗ Branch 1 not taken.
|
1511785 | step_wrapper.add("resulting_condition", *cond); |
| 10139 |
1/2✓ Branch 0 taken 1511790 times.
✗ Branch 1 not taken.
|
1511785 | } |
| 10140 | /* | ||
| 10141 | change field = field to field = const for each found field = const | ||
| 10142 | Note: Since we disable multi-equalities in the hypergraph optimizer for now, | ||
| 10143 | we also cannot run this optimization; it causes spurious “Impossible WHERE” | ||
| 10144 | in e.g. main.select_none. | ||
| 10145 | */ | ||
| 10146 |
4/4✓ Branch 0 taken 1516739 times.
✓ Branch 1 taken 5290 times.
✓ Branch 2 taken 1516680 times.
✓ Branch 3 taken 59 times.
|
1522029 | if (*cond && !thd->lex->using_hypergraph_optimizer) { |
| 10147 |
1/2✓ Branch 0 taken 1516705 times.
✗ Branch 1 not taken.
|
1516680 | Opt_trace_object step_wrapper(trace); |
| 10148 |
1/2✓ Branch 0 taken 1516713 times.
✗ Branch 1 not taken.
|
1516705 | step_wrapper.add_alnum("transformation", "constant_propagation"); |
| 10149 | { | ||
| 10150 | Opt_trace_disable_I_S disable_trace_wrapper(trace, | ||
| 10151 |
1/2✓ Branch 0 taken 1516719 times.
✗ Branch 1 not taken.
|
1516713 | !(*cond)->has_subquery()); |
| 10152 |
1/2✓ Branch 0 taken 1516702 times.
✗ Branch 1 not taken.
|
1516719 | Opt_trace_array trace_subselect(trace, "subselect_evaluation"); |
| 10153 |
3/4✓ Branch 0 taken 1516615 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1516614 times.
|
1516702 | if (propagate_cond_constants(thd, nullptr, *cond, *cond)) return true; |
| 10154 |
3/4✓ Branch 0 taken 1516634 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1516679 times.
✓ Branch 3 taken 26 times.
|
1516608 | } |
| 10155 |
1/2✓ Branch 0 taken 1516691 times.
✗ Branch 1 not taken.
|
1516679 | step_wrapper.add("resulting_condition", *cond); |
| 10156 |
1/2✓ Branch 0 taken 1516695 times.
✗ Branch 1 not taken.
|
1516717 | } |
| 10157 | |||
| 10158 | /* | ||
| 10159 | Remove all instances of item == item | ||
| 10160 | Remove all and-levels where CONST item != CONST item | ||
| 10161 | */ | ||
| 10162 |
4/6✓ Branch 0 taken 1522077 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 1522062 times.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
|
1522044 | DBUG_EXECUTE("where", |
| 10163 | print_where(thd, *cond, "after const change", QT_ORDINARY);); | ||
| 10164 |
2/2✓ Branch 0 taken 1516761 times.
✓ Branch 1 taken 5316 times.
|
1522077 | if (*cond) { |
| 10165 |
1/2✓ Branch 0 taken 1516769 times.
✗ Branch 1 not taken.
|
1516761 | Opt_trace_object step_wrapper(trace); |
| 10166 |
1/2✓ Branch 0 taken 1516771 times.
✗ Branch 1 not taken.
|
1516769 | step_wrapper.add_alnum("transformation", "trivial_condition_removal"); |
| 10167 | { | ||
| 10168 | Opt_trace_disable_I_S disable_trace_wrapper(trace, | ||
| 10169 |
1/2✓ Branch 0 taken 1516774 times.
✗ Branch 1 not taken.
|
1516771 | !(*cond)->has_subquery()); |
| 10170 |
1/2✓ Branch 0 taken 1516751 times.
✗ Branch 1 not taken.
|
1516774 | Opt_trace_array trace_subselect(trace, "subselect_evaluation"); |
| 10171 |
3/4✓ Branch 0 taken 1516678 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 1516644 times.
|
1516751 | if (remove_eq_conds(thd, *cond, cond, cond_value)) return true; |
| 10172 |
4/4✓ Branch 0 taken 1516654 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 1516708 times.
✓ Branch 3 taken 42 times.
|
1516712 | } |
| 10173 |
1/2✓ Branch 0 taken 1516701 times.
✗ Branch 1 not taken.
|
1516708 | step_wrapper.add("resulting_condition", *cond); |
| 10174 |
2/2✓ Branch 0 taken 1516706 times.
✓ Branch 1 taken 29 times.
|
1516743 | } |
| 10175 |
3/4✓ Branch 0 taken 1522019 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1522013 times.
|
1522022 | if (thd->is_error()) return true; |
| 10176 | 1522013 | return false; | |
| 10177 | 1522045 | } | |
| 10178 | |||
| 10179 | /** | ||
| 10180 | Checks if a condition can be evaluated during constant folding. It can be | ||
| 10181 | evaluated if it is constant during execution and not expensive to evaluate. If | ||
| 10182 | it contains a subquery, it should not be evaluated if the option | ||
| 10183 | OPTION_NO_SUBQUERY_DURING_OPTIMIZATION is active. | ||
| 10184 | */ | ||
| 10185 | 14089505 | static bool can_evaluate_condition(THD *thd, Item *condition) { | |
| 10186 |
4/4✓ Branch 0 taken 24575 times.
✓ Branch 1 taken 14064964 times.
✓ Branch 2 taken 24533 times.
✓ Branch 3 taken 42 times.
|
14114045 | return condition->const_for_execution() && !condition->is_expensive() && |
| 10187 |
2/2✓ Branch 0 taken 24523 times.
✓ Branch 1 taken 17 times.
|
24533 | evaluate_during_optimization(condition, |
| 10188 | 14114079 | thd->lex->current_query_block()); | |
| 10189 | } | ||
| 10190 | |||
| 10191 | /** | ||
| 10192 | Calls fold_condition. If that made the condition constant for execution, | ||
| 10193 | simplify and fold again. @see fold_condition() for arguments. | ||
| 10194 | */ | ||
| 10195 | 7868333 | static bool fold_condition_exec(THD *thd, Item *cond, Item **retcond, | |
| 10196 | Item::cond_result *cond_value) { | ||
| 10197 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 7868368 times.
|
7868333 | if (fold_condition(thd, cond, retcond, cond_value)) return true; |
| 10198 |
4/4✓ Branch 0 taken 7862448 times.
✓ Branch 1 taken 5920 times.
✓ Branch 2 taken 124 times.
✓ Branch 3 taken 7868314 times.
|
15730886 | if (*retcond != nullptr && |
| 10199 |
2/2✓ Branch 0 taken 124 times.
✓ Branch 1 taken 7862394 times.
|
7862448 | can_evaluate_condition(thd, *retcond)) // simplify further maybe |
| 10200 | 124 | return remove_eq_conds(thd, *retcond, retcond, cond_value); | |
| 10201 | 7868314 | return false; | |
| 10202 | } | ||
| 10203 | |||
| 10204 | /** | ||
| 10205 | Removes const and eq items. Returns the new item, or nullptr if no condition. | ||
| 10206 | |||
| 10207 | @param thd thread handler | ||
| 10208 | @param cond the condition to handle | ||
| 10209 | @param[out] retcond condition after const removal | ||
| 10210 | @param[out] cond_value resulting value of the condition | ||
| 10211 | =COND_OK condition must be evaluated (e.g. field = constant) | ||
| 10212 | =COND_TRUE always true (e.g. 1 = 1) | ||
| 10213 | =COND_FALSE always false (e.g. 1 = 2) | ||
| 10214 | |||
| 10215 | @returns false if success, true if error | ||
| 10216 | */ | ||
| 10217 | 7921412 | bool remove_eq_conds(THD *thd, Item *cond, Item **retcond, | |
| 10218 | Item::cond_result *cond_value) { | ||
| 10219 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7921604 times.
|
7921412 | assert(cond->real_item()->is_bool_func()); |
| 10220 |
2/2✓ Branch 0 taken 1694437 times.
✓ Branch 1 taken 6227179 times.
|
7921604 | if (cond->type() == Item::COND_ITEM) { |
| 10221 | 1694437 | Item_cond *const item_cond = down_cast<Item_cond *>(cond); | |
| 10222 |
1/2✓ Branch 0 taken 1694443 times.
✗ Branch 1 not taken.
|
1694442 | const bool and_level = item_cond->functype() == Item_func::COND_AND_FUNC; |
| 10223 |
1/2✓ Branch 0 taken 1694438 times.
✗ Branch 1 not taken.
|
1694443 | List_iterator<Item> li(*item_cond->argument_list()); |
| 10224 | 1694438 | bool should_fix_fields = false; | |
| 10225 | 1694438 | *cond_value = Item::COND_UNDEF; | |
| 10226 | Item *item; | ||
| 10227 |
2/2✓ Branch 0 taken 6404240 times.
✓ Branch 1 taken 1688265 times.
|
8092551 | while ((item = li++)) { |
| 10228 | Item *new_item; | ||
| 10229 | Item::cond_result tmp_cond_value; | ||
| 10230 |
3/4✓ Branch 0 taken 6404294 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 6404293 times.
|
6410387 | if (remove_eq_conds(thd, item, &new_item, &tmp_cond_value)) return true; |
| 10231 | |||
| 10232 |
2/2✓ Branch 0 taken 19034 times.
✓ Branch 1 taken 6385259 times.
|
6404293 | if (new_item == nullptr) |
| 10233 |
1/2✓ Branch 0 taken 19001 times.
✗ Branch 1 not taken.
|
19034 | li.remove(); |
| 10234 |
2/2✓ Branch 0 taken 741 times.
✓ Branch 1 taken 6384518 times.
|
6385259 | else if (item != new_item) { |
| 10235 | 741 | (void)li.replace(new_item); | |
| 10236 | 741 | should_fix_fields = true; | |
| 10237 | } | ||
| 10238 |
2/2✓ Branch 0 taken 1694417 times.
✓ Branch 1 taken 4709843 times.
|
6404260 | if (*cond_value == Item::COND_UNDEF) *cond_value = tmp_cond_value; |
| 10239 |
3/5✓ Branch 0 taken 6385246 times.
✓ Branch 1 taken 12863 times.
✓ Branch 2 taken 6171 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
6404260 | switch (tmp_cond_value) { |
| 10240 | 6385246 | case Item::COND_OK: // Not true or false | |
| 10241 |
4/4✓ Branch 0 taken 1019970 times.
✓ Branch 1 taken 5365276 times.
✓ Branch 2 taken 269 times.
✓ Branch 3 taken 1019701 times.
|
6385246 | if (and_level || *cond_value == Item::COND_FALSE) |
| 10242 | 5365545 | *cond_value = tmp_cond_value; | |
| 10243 | 6385246 | break; | |
| 10244 | 12863 | case Item::COND_FALSE: | |
| 10245 |
2/2✓ Branch 0 taken 5713 times.
✓ Branch 1 taken 7150 times.
|
12863 | if (and_level) // Always false |
| 10246 | { | ||
| 10247 | 5713 | *cond_value = tmp_cond_value; | |
| 10248 | 5713 | *retcond = nullptr; | |
| 10249 | 5713 | return false; | |
| 10250 | } | ||
| 10251 | 7150 | break; | |
| 10252 | 6171 | case Item::COND_TRUE: | |
| 10253 |
2/2✓ Branch 0 taken 434 times.
✓ Branch 1 taken 5737 times.
|
6171 | if (!and_level) // Always true |
| 10254 | { | ||
| 10255 | 434 | *cond_value = tmp_cond_value; | |
| 10256 | 434 | *retcond = nullptr; | |
| 10257 | 434 | return false; | |
| 10258 | } | ||
| 10259 | 5737 | break; | |
| 10260 | ✗ | case Item::COND_UNDEF: // Impossible | |
| 10261 | ✗ | assert(false); /* purecov: deadcode */ | |
| 10262 | } | ||
| 10263 | } | ||
| 10264 |
3/4✓ Branch 0 taken 520 times.
✓ Branch 1 taken 1687745 times.
✓ Branch 2 taken 520 times.
✗ Branch 3 not taken.
|
1688265 | if (should_fix_fields) item_cond->update_used_tables(); |
| 10265 | |||
| 10266 |
4/4✓ Branch 0 taken 1688039 times.
✓ Branch 1 taken 250 times.
✓ Branch 2 taken 250 times.
✓ Branch 3 taken 1688039 times.
|
3376304 | if (item_cond->argument_list()->elements == 0 || |
| 10267 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1688037 times.
|
1688039 | *cond_value != Item::COND_OK) { |
| 10268 | 250 | *retcond = nullptr; | |
| 10269 | 250 | return false; | |
| 10270 | } | ||
| 10271 |
2/2✓ Branch 0 taken 22223 times.
✓ Branch 1 taken 1665815 times.
|
1688039 | if (item_cond->argument_list()->elements == 1) { |
| 10272 | /* | ||
| 10273 | BUG#11765699: | ||
| 10274 | We're dealing with an AND or OR item that has only one | ||
| 10275 | argument. However, it is not an option to empty the list | ||
| 10276 | because: | ||
| 10277 | |||
| 10278 | - this function is called for either JOIN::conds or | ||
| 10279 | JOIN::having, but these point to the same condition as | ||
| 10280 | Query_block::where and Query_block::having do. | ||
| 10281 | |||
| 10282 | - The return value of remove_eq_conds() is assigned to | ||
| 10283 | JOIN::conds and JOIN::having, so emptying the list and | ||
| 10284 | returning the only remaining item "replaces" the AND or OR | ||
| 10285 | with item for the variables in JOIN. However, the return | ||
| 10286 | value is not assigned to the Query_block counterparts. Thus, | ||
| 10287 | if argument_list is emptied, Query_block forgets the item in | ||
| 10288 | argument_list()->head(). | ||
| 10289 | |||
| 10290 | item is therefore returned, but argument_list is not emptied. | ||
| 10291 | */ | ||
| 10292 | 22223 | item = item_cond->argument_list()->head(); | |
| 10293 | /* | ||
| 10294 | Consider reenabling the line below when the optimizer has been | ||
| 10295 | split into properly separated phases. | ||
| 10296 | |||
| 10297 | item_cond->argument_list()->empty(); | ||
| 10298 | */ | ||
| 10299 | 22221 | *retcond = item; | |
| 10300 | 22221 | return false; | |
| 10301 | } | ||
| 10302 |
2/2✓ Branch 0 taken 24399 times.
✓ Branch 1 taken 6202665 times.
|
6227179 | } else if (can_evaluate_condition(thd, cond)) { |
| 10303 | bool value; | ||
| 10304 |
3/4✓ Branch 0 taken 24399 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 24368 times.
|
24399 | if (eval_const_cond(thd, cond, &value)) return true; |
| 10305 |
2/2✓ Branch 0 taken 6482 times.
✓ Branch 1 taken 17886 times.
|
24368 | *cond_value = value ? Item::COND_TRUE : Item::COND_FALSE; |
| 10306 | 24368 | *retcond = nullptr; | |
| 10307 | 24368 | return false; | |
| 10308 | } else { // Boolean compare function | ||
| 10309 | 6202665 | *cond_value = cond->eq_cmp_result(); | |
| 10310 |
2/2✓ Branch 0 taken 5030838 times.
✓ Branch 1 taken 1171927 times.
|
6202765 | if (*cond_value == Item::COND_OK) { |
| 10311 | 5030838 | return fold_condition_exec(thd, cond, retcond, cond_value); | |
| 10312 | } | ||
| 10313 | 1171927 | Item *left_item = down_cast<Item_func *>(cond)->arguments()[0]; | |
| 10314 | 1171950 | Item *right_item = down_cast<Item_func *>(cond)->arguments()[1]; | |
| 10315 |
6/6✓ Branch 0 taken 252 times.
✓ Branch 1 taken 1171649 times.
✓ Branch 2 taken 251 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 251 times.
✓ Branch 5 taken 1171650 times.
|
1171953 | if (left_item->eq(right_item, true) && !cond->is_non_deterministic()) { |
| 10316 | /* | ||
| 10317 | Two identical items are being compared: | ||
| 10318 | 1) If the items are not nullable, return result from eq_cmp_result(), | ||
| 10319 | that is, we can short circuit because result is statically always | ||
| 10320 | known to be true or false, depending on which operator we are | ||
| 10321 | dealing with. If the operator allows equality, *cond_value is | ||
| 10322 | Item::COND_TRUE (a non-null value is always equal to itself), else | ||
| 10323 | Item::COND_FALSE (a non-null value is never unequal to itself). | ||
| 10324 | 2) If the items are nullable and the result from eq_cmp_result() is | ||
| 10325 | false, result is always false, that is, the operator doesn't | ||
| 10326 | allow for equality, the result is always false: Any non-null | ||
| 10327 | value cannot obviously be unequal to itself, and any NULL value | ||
| 10328 | would yield an undefined result (e.g. NULL < NULL | ||
| 10329 | is undefined), and hence Item::COND_FALSE in this context is the | ||
| 10330 | effective result. | ||
| 10331 | (Call order ensures test is not applied to conditions with explicit | ||
| 10332 | truth value test) | ||
| 10333 | 3) If the <=> operator is used, result is always true because | ||
| 10334 | NULL = NULL is true for this operator | ||
| 10335 | */ | ||
| 10336 |
6/6✓ Branch 0 taken 123 times.
✓ Branch 1 taken 128 times.
✓ Branch 2 taken 86 times.
✓ Branch 3 taken 37 times.
✓ Branch 4 taken 175 times.
✓ Branch 5 taken 76 times.
|
337 | if (!left_item->is_nullable() || *cond_value == Item::COND_FALSE || |
| 10337 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 76 times.
|
86 | down_cast<Item_func *>(cond)->functype() == Item_func::EQUAL_FUNC) { |
| 10338 | 175 | *retcond = nullptr; | |
| 10339 | 175 | return false; | |
| 10340 | } | ||
| 10341 | } | ||
| 10342 | } | ||
| 10343 | 2837541 | return fold_condition_exec(thd, cond, retcond, cond_value); | |
| 10344 | } | ||
| 10345 | |||
| 10346 | /** | ||
| 10347 | Check if GROUP BY/DISTINCT can be optimized away because the set is | ||
| 10348 | already known to be distinct. | ||
| 10349 | |||
| 10350 | Used in removing the GROUP BY/DISTINCT of the following types of | ||
| 10351 | statements: | ||
| 10352 | @code | ||
| 10353 | SELECT [DISTINCT] <unique_key_cols>... FROM <single_table_ref> | ||
| 10354 | [GROUP BY <unique_key_cols>,...] | ||
| 10355 | @endcode | ||
| 10356 | |||
| 10357 | If (a,b,c is distinct) | ||
| 10358 | then <any combination of a,b,c>,{whatever} is also distinct | ||
| 10359 | |||
| 10360 | This function checks if all the key parts of any of the unique keys | ||
| 10361 | of the table are referenced by a list : either the select list | ||
| 10362 | through find_field_in_item_list or GROUP BY list through | ||
| 10363 | find_field_in_order_list. | ||
| 10364 | If the above holds and the key parts cannot contain NULLs then we | ||
| 10365 | can safely remove the GROUP BY/DISTINCT, | ||
| 10366 | as no result set can be more distinct than an unique key. | ||
| 10367 | |||
| 10368 | @param tab The join table to operate on. | ||
| 10369 | @param find_func function to iterate over the list and search | ||
| 10370 | for a field | ||
| 10371 | @param data data that's passed through to to find_func | ||
| 10372 | |||
| 10373 | @retval | ||
| 10374 | 1 found | ||
| 10375 | @retval | ||
| 10376 | 0 not found. | ||
| 10377 | |||
| 10378 | @note | ||
| 10379 | The function assumes that make_outerjoin_info() has been called in | ||
| 10380 | order for the check for outer tables to work. | ||
| 10381 | */ | ||
| 10382 | |||
| 10383 | 5533 | static bool list_contains_unique_index(JOIN_TAB *tab, | |
| 10384 | bool (*find_func)(Field *, void *), | ||
| 10385 | void *data) { | ||
| 10386 | 5533 | TABLE *table = tab->table(); | |
| 10387 | |||
| 10388 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 5521 times.
|
5533 | if (tab->is_inner_table_of_outer_join()) return false; |
| 10389 |
2/2✓ Branch 0 taken 3536 times.
✓ Branch 1 taken 5057 times.
|
8593 | for (uint keynr = 0; keynr < table->s->keys; keynr++) { |
| 10390 |
2/2✓ Branch 0 taken 2322 times.
✓ Branch 1 taken 1214 times.
|
3536 | if (keynr == table->s->primary_key || |
| 10391 |
2/2✓ Branch 0 taken 658 times.
✓ Branch 1 taken 1664 times.
|
2322 | (table->key_info[keynr].flags & HA_NOSAME)) { |
| 10392 | 1872 | KEY *keyinfo = table->key_info + keynr; | |
| 10393 | KEY_PART_INFO *key_part, *key_part_end; | ||
| 10394 | |||
| 10395 | 555 | for (key_part = keyinfo->key_part, | |
| 10396 | 1872 | key_part_end = key_part + keyinfo->user_defined_key_parts; | |
| 10397 |
2/2✓ Branch 0 taken 1963 times.
✓ Branch 1 taken 464 times.
|
2427 | key_part < key_part_end; key_part++) { |
| 10398 |
6/6✓ Branch 0 taken 1576 times.
✓ Branch 1 taken 387 times.
✓ Branch 2 taken 1021 times.
✓ Branch 3 taken 555 times.
✓ Branch 4 taken 1408 times.
✓ Branch 5 taken 555 times.
|
1963 | if (key_part->field->is_nullable() || !find_func(key_part->field, data)) |
| 10399 | 1408 | break; | |
| 10400 | } | ||
| 10401 |
2/2✓ Branch 0 taken 464 times.
✓ Branch 1 taken 1408 times.
|
1872 | if (key_part == key_part_end) return true; |
| 10402 | } | ||
| 10403 | } | ||
| 10404 | 5057 | return false; | |
| 10405 | } | ||
| 10406 | |||
| 10407 | /** | ||
| 10408 | Helper function for list_contains_unique_index. | ||
| 10409 | Find a field reference in a list of ORDER structures. | ||
| 10410 | Finds a direct reference of the Field in the list. | ||
| 10411 | |||
| 10412 | @param field The field to search for. | ||
| 10413 | @param data ORDER *.The list to search in | ||
| 10414 | |||
| 10415 | @retval | ||
| 10416 | 1 found | ||
| 10417 | @retval | ||
| 10418 | 0 not found. | ||
| 10419 | */ | ||
| 10420 | |||
| 10421 | 644 | static bool find_field_in_order_list(Field *field, void *data) { | |
| 10422 | 644 | ORDER *group = (ORDER *)data; | |
| 10423 | 644 | bool part_found = false; | |
| 10424 |
2/2✓ Branch 0 taken 699 times.
✓ Branch 1 taken 316 times.
|
1015 | for (ORDER *tmp_group = group; tmp_group; tmp_group = tmp_group->next) { |
| 10425 | 699 | const Item *item = (*tmp_group->item)->real_item(); | |
| 10426 |
4/4✓ Branch 0 taken 588 times.
✓ Branch 1 taken 111 times.
✓ Branch 2 taken 328 times.
✓ Branch 3 taken 371 times.
|
1287 | if (item->type() == Item::FIELD_ITEM && |
| 10427 |
2/2✓ Branch 0 taken 328 times.
✓ Branch 1 taken 260 times.
|
588 | down_cast<const Item_field *>(item)->field->eq(field)) { |
| 10428 | 328 | part_found = true; | |
| 10429 | 328 | break; | |
| 10430 | } | ||
| 10431 | } | ||
| 10432 | 644 | return part_found; | |
| 10433 | } | ||
| 10434 | |||
| 10435 | /** | ||
| 10436 | Helper function for list_contains_unique_index. | ||
| 10437 | Find a field reference in a dynamic list of Items. | ||
| 10438 | Finds a direct reference of the Field in the list. | ||
| 10439 | |||
| 10440 | @param[in] field The field to search for. | ||
| 10441 | @param[in] data List<Item> *.The list to search in | ||
| 10442 | |||
| 10443 | @retval | ||
| 10444 | 1 found | ||
| 10445 | @retval | ||
| 10446 | 0 not found. | ||
| 10447 | */ | ||
| 10448 | |||
| 10449 | 932 | static bool find_field_in_item_list(Field *field, void *data) { | |
| 10450 | 932 | mem_root_deque<Item *> *fields = | |
| 10451 | reinterpret_cast<mem_root_deque<Item *> *>(data); | ||
| 10452 | 932 | bool part_found = false; | |
| 10453 | |||
| 10454 |
8/14✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 932 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 932 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1023 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 796 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1728 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1023 times.
✓ Branch 13 taken 705 times.
|
1728 | for (const Item *item : VisibleFields(*fields)) { |
| 10455 |
5/6✓ Branch 0 taken 1023 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 784 times.
✓ Branch 3 taken 239 times.
✓ Branch 4 taken 227 times.
✓ Branch 5 taken 796 times.
|
1807 | if (item->type() == Item::FIELD_ITEM && |
| 10456 |
3/4✓ Branch 0 taken 784 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 227 times.
✓ Branch 3 taken 557 times.
|
784 | down_cast<const Item_field *>(item)->field->eq(field)) { |
| 10457 | 227 | part_found = true; | |
| 10458 | 227 | break; | |
| 10459 | } | ||
| 10460 | } | ||
| 10461 | 932 | return part_found; | |
| 10462 | } | ||
| 10463 | |||
| 10464 | 3090 | ORDER *create_order_from_distinct(THD *thd, Ref_item_array ref_item_array, | |
| 10465 | ORDER *order_list, | ||
| 10466 | mem_root_deque<Item *> *fields, | ||
| 10467 | bool skip_aggregates, | ||
| 10468 | bool convert_bit_fields_to_long, | ||
| 10469 | bool *all_order_by_fields_used) { | ||
| 10470 | 3090 | ORDER *group = nullptr, **prev = &group; | |
| 10471 | |||
| 10472 | 3090 | *all_order_by_fields_used = true; | |
| 10473 | |||
| 10474 |
2/2✓ Branch 0 taken 309 times.
✓ Branch 1 taken 3090 times.
|
3399 | for (ORDER *order = order_list; order; order = order->next) { |
| 10475 |
2/2✓ Branch 0 taken 237 times.
✓ Branch 1 taken 72 times.
|
309 | if (order->in_field_list) { |
| 10476 |
1/2✓ Branch 0 taken 237 times.
✗ Branch 1 not taken.
|
237 | ORDER *ord = (ORDER *)thd->memdup((char *)order, sizeof(ORDER)); |
| 10477 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
|
237 | if (!ord) return nullptr; |
| 10478 | 237 | *prev = ord; | |
| 10479 | 237 | prev = &ord->next; | |
| 10480 | 237 | (*ord->item)->marker = Item::MARKER_DISTINCT_GROUP; | |
| 10481 | } else | ||
| 10482 | 72 | *all_order_by_fields_used = false; | |
| 10483 | } | ||
| 10484 | |||
| 10485 |
1/2✓ Branch 0 taken 3090 times.
✗ Branch 1 not taken.
|
3090 | Mem_root_array<std::pair<Item *, ORDER *>> bit_fields_to_add(thd->mem_root); |
| 10486 | |||
| 10487 |
8/14✓ Branch 0 taken 3090 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3090 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3090 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4421 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4421 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7511 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4421 times.
✓ Branch 13 taken 3090 times.
|
7511 | for (Item *&item : VisibleFields(*fields)) { |
| 10488 |
8/10✓ Branch 0 taken 4421 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4302 times.
✓ Branch 3 taken 119 times.
✓ Branch 4 taken 4169 times.
✓ Branch 5 taken 133 times.
✓ Branch 6 taken 4169 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 356 times.
✓ Branch 9 taken 4065 times.
|
8723 | if (!item->const_item() && (!skip_aggregates || !item->has_aggregation()) && |
| 10489 |
2/2✓ Branch 0 taken 4065 times.
✓ Branch 1 taken 237 times.
|
4302 | item->marker != Item::MARKER_DISTINCT_GROUP) { |
| 10490 | /* | ||
| 10491 | Don't put duplicate columns from the SELECT list into the | ||
| 10492 | GROUP BY list. | ||
| 10493 | */ | ||
| 10494 | ORDER *ord_iter; | ||
| 10495 |
2/2✓ Branch 0 taken 3007 times.
✓ Branch 1 taken 4054 times.
|
7061 | for (ord_iter = group; ord_iter; ord_iter = ord_iter->next) |
| 10496 |
3/4✓ Branch 0 taken 3007 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 2996 times.
|
3007 | if ((*ord_iter->item)->eq(item, true)) goto next_item; |
| 10497 | |||
| 10498 |
1/2✓ Branch 0 taken 4054 times.
✗ Branch 1 not taken.
|
4054 | ORDER *ord = (ORDER *)thd->mem_calloc(sizeof(ORDER)); |
| 10499 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4054 times.
|
4054 | if (!ord) return nullptr; |
| 10500 | |||
| 10501 |
3/4✓ Branch 0 taken 4054 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3456 times.
|
7516 | if (item->type() == Item::FIELD_ITEM && |
| 10502 |
6/6✓ Branch 0 taken 3462 times.
✓ Branch 1 taken 592 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 4049 times.
|
7516 | item->data_type() == MYSQL_TYPE_BIT && convert_bit_fields_to_long) { |
| 10503 | /* | ||
| 10504 | Because HEAP tables can't index BIT fields we need to use an | ||
| 10505 | additional hidden field for grouping because later it will be | ||
| 10506 | converted to a LONG field. Original field will remain of the | ||
| 10507 | BIT type and will be returned to a client. | ||
| 10508 | @note setup_ref_array() needs to account for the extra space. | ||
| 10509 | @note We need to defer the actual adding to after the loop, | ||
| 10510 | or we will invalidate the iterator to “fields”. | ||
| 10511 | */ | ||
| 10512 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | Item_field *new_item = new Item_field(thd, (Item_field *)item); |
| 10513 | 5 | ord->item = &item; // Temporary; for the duplicate check above. | |
| 10514 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | bit_fields_to_add.push_back(std::make_pair(new_item, ord)); |
| 10515 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 4027 times.
|
4049 | } else if (ref_item_array.is_null()) { |
| 10516 | // No slices are in use, so just use the field from the list. | ||
| 10517 | 22 | ord->item = &item; | |
| 10518 | } else { | ||
| 10519 | /* | ||
| 10520 | We have here only visible fields, so we can use simple indexing | ||
| 10521 | of ref_item_array (order in the array and in the list are same) | ||
| 10522 | */ | ||
| 10523 | 4027 | ord->item = &ref_item_array[0]; | |
| 10524 | } | ||
| 10525 | 4054 | ord->direction = ORDER_ASC; | |
| 10526 | 4054 | *prev = ord; | |
| 10527 | 4054 | prev = &ord->next; | |
| 10528 | } | ||
| 10529 | 356 | next_item: | |
| 10530 |
2/2✓ Branch 0 taken 4399 times.
✓ Branch 1 taken 22 times.
|
4421 | if (!ref_item_array.is_null()) { |
| 10531 | 4399 | ref_item_array.pop_front(); | |
| 10532 | } | ||
| 10533 | } | ||
| 10534 |
3/4✓ Branch 0 taken 3090 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 3090 times.
|
3095 | for (const auto &item_and_order : bit_fields_to_add) { |
| 10535 | 10 | item_and_order.second->item = | |
| 10536 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | thd->lex->current_query_block()->add_hidden_item(item_and_order.first); |
| 10537 | 5 | thd->lex->current_query_block()->hidden_items_from_optimization++; | |
| 10538 | } | ||
| 10539 | 3090 | *prev = nullptr; | |
| 10540 | 3090 | return group; | |
| 10541 | 3090 | } | |
| 10542 | |||
| 10543 | /** | ||
| 10544 | Return table number if there is only one table in sort order | ||
| 10545 | and group and order is compatible, else return 0. | ||
| 10546 | */ | ||
| 10547 | |||
| 10548 | 1867020 | static TABLE *get_sort_by_table(ORDER *a, ORDER *b, TABLE_LIST *tables) { | |
| 10549 |
1/2✓ Branch 0 taken 1867080 times.
✗ Branch 1 not taken.
|
1867020 | DBUG_TRACE; |
| 10550 | 1867080 | table_map map = (table_map)0; | |
| 10551 | |||
| 10552 |
2/2✓ Branch 0 taken 1315637 times.
✓ Branch 1 taken 551443 times.
|
1867080 | if (!a) |
| 10553 | 1315637 | a = b; // Only one need to be given | |
| 10554 |
2/2✓ Branch 0 taken 547876 times.
✓ Branch 1 taken 3567 times.
|
551443 | else if (!b) |
| 10555 | 547876 | b = a; | |
| 10556 | |||
| 10557 |
4/4✓ Branch 0 taken 901169 times.
✓ Branch 1 taken 1866251 times.
✓ Branch 2 taken 901135 times.
✓ Branch 3 taken 34 times.
|
2767420 | for (; a && b; a = a->next, b = b->next) { |
| 10558 |
3/4✓ Branch 0 taken 901135 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 795 times.
✓ Branch 3 taken 900340 times.
|
901135 | if (!(*a->item)->eq(*b->item, true)) return nullptr; |
| 10559 |
1/2✓ Branch 0 taken 900340 times.
✗ Branch 1 not taken.
|
900340 | map |= a->item[0]->used_tables(); |
| 10560 | } | ||
| 10561 | 1866285 | map &= ~INNER_TABLE_BIT; | |
| 10562 |
4/4✓ Branch 0 taken 570417 times.
✓ Branch 1 taken 1295868 times.
✓ Branch 2 taken 347 times.
✓ Branch 3 taken 570070 times.
|
1866285 | if (!map || (map & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT))) return nullptr; |
| 10563 | |||
| 10564 |
2/2✓ Branch 0 taken 26581 times.
✓ Branch 1 taken 570070 times.
|
596651 | for (; !(map & tables->map()); tables = tables->next_leaf) |
| 10565 | ; | ||
| 10566 |
2/2✓ Branch 0 taken 135074 times.
✓ Branch 1 taken 434996 times.
|
570070 | if (map != tables->map()) return nullptr; // More than one table |
| 10567 |
5/8✓ Branch 0 taken 434996 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 434996 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 434995 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
434996 | DBUG_PRINT("exit", ("sort by table: %d", tables->tableno())); |
| 10568 | 434996 | return tables->table; | |
| 10569 | 1867080 | } | |
| 10570 | |||
| 10571 | /** | ||
| 10572 | Update some values in keyuse for faster choose_table_order() loop. | ||
| 10573 | |||
| 10574 | @todo Check if this is the real meaning of ref_table_rows. | ||
| 10575 | */ | ||
| 10576 | |||
| 10577 | 1767443 | void JOIN::optimize_keyuse() { | |
| 10578 |
2/2✓ Branch 0 taken 4649266 times.
✓ Branch 1 taken 1767491 times.
|
6416747 | for (size_t ix = 0; ix < keyuse_array.size(); ++ix) { |
| 10579 | 4649266 | Key_use *keyuse = &keyuse_array.at(ix); | |
| 10580 | table_map map; | ||
| 10581 | /* | ||
| 10582 | If we find a ref, assume this table matches a proportional | ||
| 10583 | part of this table. | ||
| 10584 | For example 100 records matching a table with 5000 records | ||
| 10585 | gives 5000/100 = 50 records per key | ||
| 10586 | Constant tables are ignored. | ||
| 10587 | To avoid bad matches, we don't make ref_table_rows less than 100. | ||
| 10588 | */ | ||
| 10589 | 4649354 | keyuse->ref_table_rows = ~(ha_rows)0; // If no ref | |
| 10590 | 4649354 | if (keyuse->used_tables & | |
| 10591 |
2/2✓ Branch 0 taken 4068061 times.
✓ Branch 1 taken 581293 times.
|
4649354 | (map = keyuse->used_tables & ~(const_table_map | PSEUDO_TABLE_BITS))) { |
| 10592 | uint tableno; | ||
| 10593 |
2/2✓ Branch 0 taken 15156384 times.
✓ Branch 1 taken 4068061 times.
|
19224445 | for (tableno = 0; !(map & 1); map >>= 1, tableno++) { |
| 10594 | } | ||
| 10595 |
2/2✓ Branch 0 taken 4067280 times.
✓ Branch 1 taken 781 times.
|
4068061 | if (map == 1) // Only one table |
| 10596 | { | ||
| 10597 | 4067280 | TABLE *tmp_table = join_tab[tableno].table(); | |
| 10598 | |||
| 10599 | 4067230 | keyuse->ref_table_rows = | |
| 10600 | 4067284 | max<ha_rows>(tmp_table->file->stats.records, 100); | |
| 10601 | } | ||
| 10602 | } | ||
| 10603 | /* | ||
| 10604 | Outer reference (external field) is constant for single executing | ||
| 10605 | of subquery | ||
| 10606 | */ | ||
| 10607 |
2/2✓ Branch 0 taken 5379 times.
✓ Branch 1 taken 4643925 times.
|
4649304 | if (keyuse->used_tables == OUTER_REF_TABLE_BIT) keyuse->ref_table_rows = 1; |
| 10608 | } | ||
| 10609 | 1767491 | } | |
| 10610 | |||
| 10611 | /** | ||
| 10612 | Function sets FT hints, initializes FT handlers | ||
| 10613 | and checks if FT index can be used as covered. | ||
| 10614 | */ | ||
| 10615 | |||
| 10616 | 2335 | bool JOIN::optimize_fts_query() { | |
| 10617 |
3/6✓ Branch 0 taken 2335 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2335 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2335 times.
✗ Branch 5 not taken.
|
2335 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 10618 | |||
| 10619 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2335 times.
|
2335 | assert(query_block->has_ft_funcs()); |
| 10620 | |||
| 10621 | // Only used by the old optimizer. | ||
| 10622 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2335 times.
|
2335 | assert(!thd->lex->using_hypergraph_optimizer); |
| 10623 | |||
| 10624 |
2/2✓ Branch 0 taken 4946 times.
✓ Branch 1 taken 2335 times.
|
7281 | for (uint i = const_tables; i < tables; i++) { |
| 10625 | 4946 | JOIN_TAB *tab = best_ref[i]; | |
| 10626 |
2/2✓ Branch 0 taken 2776 times.
✓ Branch 1 taken 2170 times.
|
4946 | if (tab->type() != JT_FT) continue; |
| 10627 | |||
| 10628 | Item_func_match *ifm; | ||
| 10629 | Item_func_match *ft_func = | ||
| 10630 | 2170 | down_cast<Item_func_match *>(tab->position()->key->val); | |
| 10631 |
1/2✓ Branch 0 taken 2170 times.
✗ Branch 1 not taken.
|
2170 | List_iterator<Item_func_match> li(*(query_block->ftfunc_list)); |
| 10632 | |||
| 10633 |
2/2✓ Branch 0 taken 2306 times.
✓ Branch 1 taken 2170 times.
|
4476 | while ((ifm = li++)) { |
| 10634 |
6/6✓ Branch 0 taken 2271 times.
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 2196 times.
✓ Branch 4 taken 110 times.
✓ Branch 5 taken 2196 times.
|
2306 | if (!(ifm->used_tables() & tab->table_ref->map()) || ifm->master) |
| 10635 | 110 | continue; | |
| 10636 | |||
| 10637 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 2170 times.
|
2196 | if (ifm != ft_func) { |
| 10638 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 20 times.
|
26 | if (ifm->can_skip_ranking()) |
| 10639 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | ifm->set_hints(this, FT_NO_RANKING, HA_POS_ERROR, false); |
| 10640 | } | ||
| 10641 | } | ||
| 10642 | |||
| 10643 | /* | ||
| 10644 | Check if internal sorting is needed. FT_SORTED flag is set | ||
| 10645 | if no ORDER BY clause or ORDER BY MATCH function is the same | ||
| 10646 | as the function that is used for FT index and FT table is | ||
| 10647 | the first non-constant table in the JOIN. | ||
| 10648 | */ | ||
| 10649 |
8/8✓ Branch 0 taken 2145 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 978 times.
✓ Branch 3 taken 1167 times.
✓ Branch 4 taken 64 times.
✓ Branch 5 taken 914 times.
✓ Branch 6 taken 931 times.
✓ Branch 7 taken 1239 times.
|
3212 | if (i == const_tables && !(ft_func->get_hints()->get_flags() & FT_BOOL) && |
| 10650 |
3/4✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 47 times.
|
1042 | (order.empty() || ft_func == test_if_ft_index_order(order.order))) |
| 10651 |
1/2✓ Branch 0 taken 931 times.
✗ Branch 1 not taken.
|
931 | ft_func->set_hints(this, FT_SORTED, m_select_limit, false); |
| 10652 | |||
| 10653 | /* | ||
| 10654 | Check if ranking is not needed. FT_NO_RANKING flag is set if | ||
| 10655 | MATCH function is used only in WHERE condition and MATCH | ||
| 10656 | function is not part of an expression. | ||
| 10657 | */ | ||
| 10658 |
2/2✓ Branch 0 taken 1279 times.
✓ Branch 1 taken 891 times.
|
2170 | if (ft_func->can_skip_ranking()) |
| 10659 |
3/4✓ Branch 0 taken 1233 times.
✓ Branch 1 taken 46 times.
✓ Branch 2 taken 1279 times.
✗ Branch 3 not taken.
|
1279 | ft_func->set_hints(this, FT_NO_RANKING, |
| 10660 | 1279 | order.empty() ? m_select_limit : HA_POS_ERROR, false); | |
| 10661 | } | ||
| 10662 | |||
| 10663 | 2335 | return init_ftfuncs(thd, query_block); | |
| 10664 | } | ||
| 10665 | |||
| 10666 | /** | ||
| 10667 | Check if FTS index only access is possible. | ||
| 10668 | |||
| 10669 | @param tab pointer to JOIN_TAB structure. | ||
| 10670 | |||
| 10671 | @return true if index only access is possible, | ||
| 10672 | false otherwise. | ||
| 10673 | */ | ||
| 10674 | |||
| 10675 | 2177 | bool JOIN::fts_index_access(JOIN_TAB *tab) { | |
| 10676 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2177 times.
|
2177 | assert(tab->type() == JT_FT); |
| 10677 | 2177 | TABLE *table = tab->table(); | |
| 10678 | |||
| 10679 | // Give up if index-only access has already been disabled on this table. | ||
| 10680 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2177 times.
|
2177 | if (table->no_keyread) { |
| 10681 | ✗ | return false; | |
| 10682 | } | ||
| 10683 | |||
| 10684 |
2/2✓ Branch 0 taken 239 times.
✓ Branch 1 taken 1938 times.
|
2177 | if ((table->file->ha_table_flags() & HA_CAN_FULLTEXT_EXT) == 0) |
| 10685 | 239 | return false; // Optimizations requires extended FTS support by table | |
| 10686 | // engine | ||
| 10687 | |||
| 10688 | /* | ||
| 10689 | This optimization does not work with filesort nor GROUP BY | ||
| 10690 | */ | ||
| 10691 |
4/4✓ Branch 0 taken 1932 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 1872 times.
|
3870 | if (grouped || |
| 10692 |
4/4✓ Branch 0 taken 90 times.
✓ Branch 1 taken 1842 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 30 times.
|
1932 | (!order.empty() && m_ordered_index_usage != ORDERED_INDEX_ORDER_BY)) |
| 10693 | 66 | return false; | |
| 10694 | |||
| 10695 | /* | ||
| 10696 | Check whether the FTS result is covering. If only document id | ||
| 10697 | and rank is needed, there is no need to access table rows. | ||
| 10698 | */ | ||
| 10699 |
2/2✓ Branch 0 taken 1946 times.
✓ Branch 1 taken 57 times.
|
2003 | for (uint i = bitmap_get_first_set(table->read_set); i < table->s->fields; |
| 10700 | 131 | i = bitmap_get_next_set(table->read_set, i)) { | |
| 10701 |
4/4✓ Branch 0 taken 131 times.
✓ Branch 1 taken 1815 times.
✓ Branch 2 taken 1815 times.
✓ Branch 3 taken 131 times.
|
2077 | if (table->field[i] != table->fts_doc_id_field || |
| 10702 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
|
131 | !tab->ft_func()->docid_in_result()) |
| 10703 | 1815 | return false; | |
| 10704 | } | ||
| 10705 | |||
| 10706 | 57 | return true; | |
| 10707 | } | ||
| 10708 | |||
| 10709 | /** | ||
| 10710 | For {semijoin,subquery} materialization: calculates various cost | ||
| 10711 | information, based on a plan in join->best_positions covering the | ||
| 10712 | to-be-materialized query block and only this. | ||
| 10713 | |||
| 10714 | @param join JOIN where plan can be found | ||
| 10715 | @param sj_nest sj materialization nest (NULL if subquery materialization) | ||
| 10716 | @param n_tables number of to-be-materialized tables | ||
| 10717 | @param[out] sjm where computed costs will be stored | ||
| 10718 | |||
| 10719 | @note that this function modifies join->map2table, which has to be filled | ||
| 10720 | correctly later. | ||
| 10721 | */ | ||
| 10722 | 11033 | static void calculate_materialization_costs(JOIN *join, TABLE_LIST *sj_nest, | |
| 10723 | uint n_tables, | ||
| 10724 | Semijoin_mat_optimize *sjm) { | ||
| 10725 | double mat_cost; // Estimated cost of materialization | ||
| 10726 | double mat_rowcount; // Estimated row count before duplicate removal | ||
| 10727 | double distinct_rowcount; // Estimated rowcount after duplicate removal | ||
| 10728 | mem_root_deque<Item *> *inner_expr_list; | ||
| 10729 | |||
| 10730 |
2/2✓ Branch 0 taken 8684 times.
✓ Branch 1 taken 2349 times.
|
11033 | if (sj_nest) { |
| 10731 | /* | ||
| 10732 | get_partial_join_cost() assumes a regular join, which is correct when | ||
| 10733 | we optimize a sj-materialization nest (always executed as regular | ||
| 10734 | join). | ||
| 10735 | */ | ||
| 10736 |
1/2✓ Branch 0 taken 8684 times.
✗ Branch 1 not taken.
|
8684 | get_partial_join_cost(join, n_tables, &mat_cost, &mat_rowcount); |
| 10737 | 8684 | n_tables += join->const_tables; | |
| 10738 | 8684 | inner_expr_list = &sj_nest->nested_join->sj_inner_exprs; | |
| 10739 | } else { | ||
| 10740 | 2349 | mat_cost = join->best_read; | |
| 10741 | 2349 | mat_rowcount = static_cast<double>(join->best_rowcount); | |
| 10742 | 2349 | inner_expr_list = &join->query_block->fields; | |
| 10743 | } | ||
| 10744 | |||
| 10745 | /* | ||
| 10746 | Adjust output cardinality estimates. If the subquery has form | ||
| 10747 | |||
| 10748 | ... oe IN (SELECT t1.colX, t2.colY, func(X,Y,Z) ) | ||
| 10749 | |||
| 10750 | then the number of distinct output record combinations has an | ||
| 10751 | upper bound of product of number of records matching the tables | ||
| 10752 | that are used by the SELECT clause. | ||
| 10753 | TODO: | ||
| 10754 | We can get a more precise estimate if we | ||
| 10755 | - use rec_per_key cardinality estimates. For simple cases like | ||
| 10756 | "oe IN (SELECT t.key ...)" it is trivial. | ||
| 10757 | - Functional dependencies between the tables in the semi-join | ||
| 10758 | nest (the payoff is probably less here?) | ||
| 10759 | */ | ||
| 10760 | { | ||
| 10761 |
2/2✓ Branch 0 taken 21813 times.
✓ Branch 1 taken 11033 times.
|
32846 | for (uint i = 0; i < n_tables; i++) { |
| 10762 | 21813 | JOIN_TAB *const tab = join->best_positions[i].table; | |
| 10763 | 21813 | join->map2table[tab->table_ref->tableno()] = tab; | |
| 10764 | } | ||
| 10765 | 11033 | table_map map = 0; | |
| 10766 |
7/12✓ Branch 0 taken 11033 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11033 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11033 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12040 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 23073 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 12040 times.
✓ Branch 11 taken 11033 times.
|
23073 | for (Item *item : VisibleFields(*inner_expr_list)) { |
| 10767 |
2/4✓ Branch 0 taken 12040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12040 times.
✗ Branch 3 not taken.
|
12040 | map |= item->used_tables(); |
| 10768 | } | ||
| 10769 | 11033 | map &= ~PSEUDO_TABLE_BITS; | |
| 10770 | 11033 | Table_map_iterator tm_it(map); | |
| 10771 | int tableno; | ||
| 10772 | 11033 | double rows = 1.0; | |
| 10773 |
2/2✓ Branch 0 taken 11354 times.
✓ Branch 1 taken 11033 times.
|
22387 | while ((tableno = tm_it.next_bit()) != Table_map_iterator::BITMAP_END) |
| 10774 | 11354 | rows *= join->map2table[tableno]->table()->quick_condition_rows; | |
| 10775 | 11033 | distinct_rowcount = min(mat_rowcount, rows); | |
| 10776 | } | ||
| 10777 | /* | ||
| 10778 | Calculate temporary table parameters and usage costs | ||
| 10779 | */ | ||
| 10780 |
1/2✓ Branch 0 taken 11033 times.
✗ Branch 1 not taken.
|
11033 | const uint rowlen = get_tmp_table_rec_length(*inner_expr_list); |
| 10781 | |||
| 10782 |
1/2✓ Branch 0 taken 11033 times.
✗ Branch 1 not taken.
|
11033 | const Cost_model_server *cost_model = join->cost_model(); |
| 10783 | |||
| 10784 | Cost_model_server::enum_tmptable_type tmp_table_type; | ||
| 10785 |
2/2✓ Branch 0 taken 10995 times.
✓ Branch 1 taken 38 times.
|
11033 | if (rowlen * distinct_rowcount < join->thd->variables.max_heap_table_size) |
| 10786 | 10995 | tmp_table_type = Cost_model_server::MEMORY_TMPTABLE; | |
| 10787 | else | ||
| 10788 | 38 | tmp_table_type = Cost_model_server::DISK_TMPTABLE; | |
| 10789 | |||
| 10790 | /* | ||
| 10791 | Let materialization cost include the cost to create the temporary | ||
| 10792 | table and write the rows into it: | ||
| 10793 | */ | ||
| 10794 | 11033 | mat_cost += cost_model->tmptable_create_cost(tmp_table_type); | |
| 10795 | 11033 | mat_cost += | |
| 10796 | 11033 | cost_model->tmptable_readwrite_cost(tmp_table_type, mat_rowcount, 0.0); | |
| 10797 | |||
| 10798 | 11033 | sjm->materialization_cost.reset(); | |
| 10799 | 11033 | sjm->materialization_cost.add_io(mat_cost); | |
| 10800 | |||
| 10801 | 11033 | sjm->expected_rowcount = distinct_rowcount; | |
| 10802 | |||
| 10803 | /* | ||
| 10804 | Set the cost to do a full scan of the temptable (will need this to | ||
| 10805 | consider doing sjm-scan): | ||
| 10806 | */ | ||
| 10807 | 11033 | sjm->scan_cost.reset(); | |
| 10808 |
2/2✓ Branch 0 taken 11012 times.
✓ Branch 1 taken 21 times.
|
11033 | if (distinct_rowcount > 0.0) { |
| 10809 | 11012 | const double scan_cost = cost_model->tmptable_readwrite_cost( | |
| 10810 | tmp_table_type, 0.0, distinct_rowcount); | ||
| 10811 | 11012 | sjm->scan_cost.add_io(scan_cost); | |
| 10812 | } | ||
| 10813 | |||
| 10814 | // The cost to lookup a row in temp. table | ||
| 10815 | const double row_cost = | ||
| 10816 | 11033 | cost_model->tmptable_readwrite_cost(tmp_table_type, 0.0, 1.0); | |
| 10817 | 11033 | sjm->lookup_cost.reset(); | |
| 10818 | 11033 | sjm->lookup_cost.add_io(row_cost); | |
| 10819 | 11033 | } | |
| 10820 | |||
| 10821 | /** | ||
| 10822 | Decides between EXISTS and materialization; performs last steps to set up | ||
| 10823 | the chosen strategy. | ||
| 10824 | @returns 'false' if no error | ||
| 10825 | |||
| 10826 | @note If UNION this is called on each contained JOIN. | ||
| 10827 | |||
| 10828 | */ | ||
| 10829 | 106041 | bool JOIN::decide_subquery_strategy() { | |
| 10830 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 106041 times.
|
106041 | assert(query_expression()->item); |
| 10831 | |||
| 10832 |
3/4✓ Branch 0 taken 106041 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12569 times.
✓ Branch 3 taken 93472 times.
|
106041 | switch (query_expression()->item->substype()) { |
| 10833 | 12569 | case Item_subselect::IN_SUBS: | |
| 10834 | case Item_subselect::ALL_SUBS: | ||
| 10835 | case Item_subselect::ANY_SUBS: | ||
| 10836 | // All of those are children of Item_in_subselect and may use EXISTS | ||
| 10837 | 12569 | break; | |
| 10838 | 93472 | default: | |
| 10839 | 93472 | return false; | |
| 10840 | } | ||
| 10841 | |||
| 10842 | Item_in_subselect *const in_pred = | ||
| 10843 | 12569 | static_cast<Item_in_subselect *>(query_expression()->item); | |
| 10844 | |||
| 10845 | 12569 | Subquery_strategy chosen_method = in_pred->strategy; | |
| 10846 | // Materialization does not allow UNION so this can't happen: | ||
| 10847 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12569 times.
|
12569 | assert(chosen_method != Subquery_strategy::SUBQ_MATERIALIZATION); |
| 10848 | |||
| 10849 |
3/4✓ Branch 0 taken 12261 times.
✓ Branch 1 taken 308 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12569 times.
|
24830 | if ((chosen_method == Subquery_strategy::CANDIDATE_FOR_IN2EXISTS_OR_MAT) && |
| 10850 |
2/4✓ Branch 0 taken 12261 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12261 times.
|
12261 | compare_costs_of_subquery_strategies(&chosen_method)) |
| 10851 | ✗ | return true; | |
| 10852 | |||
| 10853 |
2/3✓ Branch 0 taken 10458 times.
✓ Branch 1 taken 2111 times.
✗ Branch 2 not taken.
|
12569 | switch (chosen_method) { |
| 10854 | 10458 | case Subquery_strategy::SUBQ_EXISTS: | |
| 10855 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 10450 times.
|
10458 | if (query_block->m_windows.elements > 0) // grep for WL#10431 |
| 10856 | { | ||
| 10857 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | my_error(ER_NOT_SUPPORTED_YET, MYF(0), |
| 10858 | "the combination of this ALL/ANY/SOME/IN subquery with this" | ||
| 10859 | " comparison operator and with contained window functions"); | ||
| 10860 | 8 | return true; | |
| 10861 | } | ||
| 10862 |
1/2✓ Branch 0 taken 10450 times.
✗ Branch 1 not taken.
|
10450 | return in_pred->finalize_exists_transform(thd, query_block); |
| 10863 | 2111 | case Subquery_strategy::SUBQ_MATERIALIZATION: | |
| 10864 |
1/2✓ Branch 0 taken 2111 times.
✗ Branch 1 not taken.
|
2111 | return in_pred->finalize_materialization_transform(thd, this); |
| 10865 | ✗ | default: | |
| 10866 | ✗ | assert(false); | |
| 10867 | return true; | ||
| 10868 | } | ||
| 10869 | } | ||
| 10870 | |||
| 10871 | /** | ||
| 10872 | Tells what is the cheapest between IN->EXISTS and subquery materialization, | ||
| 10873 | in terms of cost, for the subquery's JOIN. | ||
| 10874 | Input: | ||
| 10875 | - join->{best_positions,best_read,best_rowcount} must contain the | ||
| 10876 | execution plan of EXISTS (where 'join' is the subquery's JOIN) | ||
| 10877 | - join2->{best_positions,best_read,best_rowcount} must be correctly set | ||
| 10878 | (where 'join2' is the parent join, the grandparent join, etc). | ||
| 10879 | Output: | ||
| 10880 | join->{best_positions,best_read,best_rowcount} contain the cheapest | ||
| 10881 | execution plan (where 'join' is the subquery's JOIN). | ||
| 10882 | |||
| 10883 | This plan choice has to happen before calling functions which set up | ||
| 10884 | execution structures, like JOIN::get_best_combination(). | ||
| 10885 | |||
| 10886 | @param[out] method chosen method (EXISTS or materialization) will be put | ||
| 10887 | here. | ||
| 10888 | @returns false if success | ||
| 10889 | */ | ||
| 10890 | 12261 | bool JOIN::compare_costs_of_subquery_strategies(Subquery_strategy *method) { | |
| 10891 | 12261 | *method = Subquery_strategy::SUBQ_EXISTS; | |
| 10892 | |||
| 10893 |
1/2✓ Branch 0 taken 12261 times.
✗ Branch 1 not taken.
|
12261 | Subquery_strategy allowed_strategies = query_block->subquery_strategy(thd); |
| 10894 | |||
| 10895 | /* | ||
| 10896 | A non-deterministic subquery should not use materialization, unless forced. | ||
| 10897 | For a detailed explanation, see Query_block::decorrelate_where_cond(). | ||
| 10898 | Here, the same logic is applied also for subqueries that are not converted | ||
| 10899 | to semi-join. | ||
| 10900 | */ | ||
| 10901 |
4/4✓ Branch 0 taken 1087 times.
✓ Branch 1 taken 11174 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 12255 times.
|
13348 | if (allowed_strategies == Subquery_strategy::CANDIDATE_FOR_IN2EXISTS_OR_MAT && |
| 10902 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1081 times.
|
1087 | (query_expression()->uncacheable & UNCACHEABLE_RAND)) |
| 10903 | 6 | allowed_strategies = Subquery_strategy::SUBQ_EXISTS; | |
| 10904 | |||
| 10905 |
2/2✓ Branch 0 taken 7354 times.
✓ Branch 1 taken 4907 times.
|
12261 | if (allowed_strategies == Subquery_strategy::SUBQ_EXISTS) return false; |
| 10906 | |||
| 10907 |
3/4✓ Branch 0 taken 3826 times.
✓ Branch 1 taken 1081 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3826 times.
|
4907 | assert(allowed_strategies == |
| 10908 | Subquery_strategy::CANDIDATE_FOR_IN2EXISTS_OR_MAT || | ||
| 10909 | allowed_strategies == Subquery_strategy::SUBQ_MATERIALIZATION); | ||
| 10910 | |||
| 10911 | 4907 | const JOIN *parent_join = query_expression()->outer_query_block()->join; | |
| 10912 |
4/4✓ Branch 0 taken 4872 times.
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 762 times.
✓ Branch 3 taken 4110 times.
|
4907 | if (!parent_join || !parent_join->child_subquery_can_materialize) |
| 10913 | 797 | return false; | |
| 10914 | |||
| 10915 | Item_in_subselect *const in_pred = | ||
| 10916 | 4110 | static_cast<Item_in_subselect *>(query_expression()->item); | |
| 10917 | |||
| 10918 | /* | ||
| 10919 | Testing subquery_allows_etc() at each optimization is necessary as each | ||
| 10920 | execution of a prepared statement may use a different type of parameter. | ||
| 10921 | */ | ||
| 10922 |
2/2✓ Branch 0 taken 1761 times.
✓ Branch 1 taken 2349 times.
|
4110 | if (!in_pred->subquery_allows_materialization( |
| 10923 |
1/2✓ Branch 0 taken 4110 times.
✗ Branch 1 not taken.
|
4110 | thd, query_block, query_block->outer_query_block())) |
| 10924 | 1761 | return false; | |
| 10925 | |||
| 10926 | 2349 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 10927 |
1/2✓ Branch 0 taken 2349 times.
✗ Branch 1 not taken.
|
2349 | Opt_trace_object trace_wrapper(trace); |
| 10928 | Opt_trace_object trace_subqmat( | ||
| 10929 |
1/2✓ Branch 0 taken 2349 times.
✗ Branch 1 not taken.
|
2349 | trace, "execution_plan_for_potential_materialization"); |
| 10930 | 2349 | const double saved_best_read = best_read; | |
| 10931 | 2349 | const ha_rows saved_best_rowcount = best_rowcount; | |
| 10932 | 2349 | POSITION *const saved_best_pos = best_positions; | |
| 10933 | |||
| 10934 |
2/2✓ Branch 0 taken 2069 times.
✓ Branch 1 taken 280 times.
|
2349 | if (in_pred->in2exists_added_to_where()) { |
| 10935 |
1/2✓ Branch 0 taken 2069 times.
✗ Branch 1 not taken.
|
2069 | Opt_trace_array trace_subqmat_steps(trace, "steps"); |
| 10936 | |||
| 10937 | // Up to one extra slot per semi-join nest is needed (if materialized) | ||
| 10938 | 2069 | const uint sj_nests = query_block->sj_nests.size(); | |
| 10939 | |||
| 10940 |
2/4✓ Branch 0 taken 2069 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2069 times.
|
2069 | if (!(best_positions = new (thd->mem_root) POSITION[tables + sj_nests])) |
| 10941 | ✗ | return true; | |
| 10942 | |||
| 10943 | // Compute plans which do not use outer references | ||
| 10944 | |||
| 10945 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2069 times.
|
2069 | assert(allow_outer_refs); |
| 10946 | 2069 | allow_outer_refs = false; | |
| 10947 | |||
| 10948 |
2/4✓ Branch 0 taken 2069 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2069 times.
|
2069 | if (optimize_semijoin_nests_for_materialization(this)) return true; |
| 10949 | |||
| 10950 |
3/6✓ Branch 0 taken 2069 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2069 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2069 times.
|
2069 | if (Optimize_table_order(thd, this, nullptr).choose_table_order()) |
| 10951 | ✗ | return true; | |
| 10952 |
1/2✓ Branch 0 taken 2069 times.
✗ Branch 1 not taken.
|
2069 | } else { |
| 10953 | /* | ||
| 10954 | If IN->EXISTS didn't add any condition to WHERE (only to HAVING, which | ||
| 10955 | can happen if subquery has aggregates) then the plan for materialization | ||
| 10956 | will be the same as for EXISTS - don't compute it again. | ||
| 10957 | */ | ||
| 10958 |
1/2✓ Branch 0 taken 280 times.
✗ Branch 1 not taken.
|
280 | trace_subqmat.add("surely_same_plan_as_EXISTS", true) |
| 10959 |
1/2✓ Branch 0 taken 280 times.
✗ Branch 1 not taken.
|
280 | .add_alnum("cause", "EXISTS_did_not_change_WHERE"); |
| 10960 | } | ||
| 10961 | |||
| 10962 | 2349 | Semijoin_mat_optimize sjm; | |
| 10963 |
1/2✓ Branch 0 taken 2349 times.
✗ Branch 1 not taken.
|
2349 | calculate_materialization_costs(this, nullptr, primary_tables, &sjm); |
| 10964 | |||
| 10965 | /* | ||
| 10966 | The number of evaluations of the subquery influences costs, we need to | ||
| 10967 | compute it. | ||
| 10968 | */ | ||
| 10969 |
1/2✓ Branch 0 taken 2349 times.
✗ Branch 1 not taken.
|
2349 | Opt_trace_object trace_subq_mat_decision(trace, "subq_mat_decision"); |
| 10970 |
1/2✓ Branch 0 taken 2349 times.
✗ Branch 1 not taken.
|
2349 | const double subq_executions = calculate_subquery_executions(in_pred, trace); |
| 10971 | 2349 | const double cost_exists = subq_executions * saved_best_read; | |
| 10972 | 2349 | const double cost_mat_table = sjm.materialization_cost.total_cost(); | |
| 10973 | const double cost_mat = | ||
| 10974 | 2349 | cost_mat_table + subq_executions * sjm.lookup_cost.total_cost(); | |
| 10975 | 2349 | const bool mat_chosen = | |
| 10976 | (allowed_strategies == Subquery_strategy::CANDIDATE_FOR_IN2EXISTS_OR_MAT) | ||
| 10977 |
4/4✓ Branch 0 taken 416 times.
✓ Branch 1 taken 1933 times.
✓ Branch 2 taken 178 times.
✓ Branch 3 taken 238 times.
|
2349 | ? (cost_mat < cost_exists) |
| 10978 | : true; | ||
| 10979 | trace_subq_mat_decision | ||
| 10980 |
1/2✓ Branch 0 taken 2349 times.
✗ Branch 1 not taken.
|
2349 | .add("cost_to_create_and_fill_materialized_table", cost_mat_table) |
| 10981 |
1/2✓ Branch 0 taken 2349 times.
✗ Branch 1 not taken.
|
2349 | .add("cost_of_one_EXISTS", saved_best_read) |
| 10982 |
1/2✓ Branch 0 taken 2349 times.
✗ Branch 1 not taken.
|
2349 | .add("number_of_subquery_evaluations", subq_executions) |
| 10983 |
1/2✓ Branch 0 taken 2349 times.
✗ Branch 1 not taken.
|
2349 | .add("cost_of_materialization", cost_mat) |
| 10984 |
1/2✓ Branch 0 taken 2349 times.
✗ Branch 1 not taken.
|
2349 | .add("cost_of_EXISTS", cost_exists) |
| 10985 |
1/2✓ Branch 0 taken 2349 times.
✗ Branch 1 not taken.
|
2349 | .add("chosen", mat_chosen); |
| 10986 |
2/2✓ Branch 0 taken 2111 times.
✓ Branch 1 taken 238 times.
|
2349 | if (mat_chosen) { |
| 10987 | 2111 | *method = Subquery_strategy::SUBQ_MATERIALIZATION; | |
| 10988 | } else { | ||
| 10989 | 238 | best_read = saved_best_read; | |
| 10990 | 238 | best_rowcount = saved_best_rowcount; | |
| 10991 | 238 | best_positions = saved_best_pos; | |
| 10992 | /* | ||
| 10993 | Don't restore JOIN::positions or best_ref, they're not used | ||
| 10994 | afterwards. best_positions is (like: by get_sj_strategy()). | ||
| 10995 | */ | ||
| 10996 | } | ||
| 10997 | 2349 | return false; | |
| 10998 | 2349 | } | |
| 10999 | |||
| 11000 | 15625 | double calculate_subquery_executions(const Item_subselect *subquery, | |
| 11001 | Opt_trace_context *trace) { | ||
| 11002 |
1/2✓ Branch 0 taken 15625 times.
✗ Branch 1 not taken.
|
15625 | Opt_trace_array trace_parents(trace, "parent_fanouts"); |
| 11003 | 15625 | double subquery_executions = 1.0; | |
| 11004 | for (;;) { | ||
| 11005 | const Query_block *const parent_query_block = | ||
| 11006 | 19971 | subquery->unit->outer_query_block(); | |
| 11007 | 19971 | const JOIN *const parent_join = parent_query_block->join; | |
| 11008 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19971 times.
|
19971 | if (parent_join == nullptr) { |
| 11009 | /* | ||
| 11010 | May be single-table UPDATE/DELETE, has no join. | ||
| 11011 | @todo we should find how many rows it plans to UPDATE/DELETE, taking | ||
| 11012 | inspiration in Explain_table::explain_rows_and_filtered(). | ||
| 11013 | This is not a priority as it applies only to | ||
| 11014 | UPDATE - child(non-mat-subq) - grandchild(may-be-mat-subq). | ||
| 11015 | And it will autosolve the day UPDATE gets a JOIN. | ||
| 11016 | */ | ||
| 11017 | ✗ | break; | |
| 11018 | } | ||
| 11019 | |||
| 11020 |
1/2✓ Branch 0 taken 19971 times.
✗ Branch 1 not taken.
|
19971 | Opt_trace_object trace_parent(trace); |
| 11021 |
1/2✓ Branch 0 taken 19971 times.
✗ Branch 1 not taken.
|
19971 | trace_parent.add_select_number(parent_query_block->select_number); |
| 11022 | double parent_fanout; | ||
| 11023 | 19971 | if ( // safety, not sure needed | |
| 11024 |
4/4✓ Branch 0 taken 15639 times.
✓ Branch 1 taken 4332 times.
✓ Branch 2 taken 4332 times.
✓ Branch 3 taken 15639 times.
|
35610 | parent_join->plan_is_const() || |
| 11025 | // if subq is in condition on constant table: | ||
| 11026 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15639 times.
|
15639 | !parent_join->child_subquery_can_materialize) { |
| 11027 | 4332 | parent_fanout = 1.0; | |
| 11028 |
1/2✓ Branch 0 taken 4332 times.
✗ Branch 1 not taken.
|
4332 | trace_parent.add("subq_attached_to_const_table", true); |
| 11029 | } else { | ||
| 11030 |
2/2✓ Branch 0 taken 10405 times.
✓ Branch 1 taken 5234 times.
|
15639 | if (subquery->in_cond_of_tab != NO_PLAN_IDX) { |
| 11031 | /* | ||
| 11032 | Subquery is attached to a certain 'pos', pos[-1].prefix_rowcount | ||
| 11033 | is the number of times we'll start a loop accessing 'pos'; each such | ||
| 11034 | loop will read pos->rows_fetched rows of 'pos', so subquery will | ||
| 11035 | be evaluated pos[-1].prefix_rowcount * pos->rows_fetched times. | ||
| 11036 | Exceptions: | ||
| 11037 | - if 'pos' is first, use 1.0 instead of pos[-1].prefix_rowcount | ||
| 11038 | - if 'pos' is first of a sj-materialization nest, same. | ||
| 11039 | |||
| 11040 | If in a sj-materialization nest, pos->rows_fetched and | ||
| 11041 | pos[-1].prefix_rowcount are of the "nest materialization" plan | ||
| 11042 | (copied back in fix_semijoin_strategies()), which is | ||
| 11043 | appropriate as it corresponds to evaluations of our subquery. | ||
| 11044 | |||
| 11045 | pos->prefix_rowcount is not suitable because if we have: | ||
| 11046 | select ... from ot1 where ot1.col in | ||
| 11047 | (select it1.col1 from it1 where it1.col2 not in (subq)); | ||
| 11048 | and subq does subq-mat, and plan is ot1 - it1+firstmatch(ot1), | ||
| 11049 | then: | ||
| 11050 | - t1.prefix_rowcount==1 (due to firstmatch) | ||
| 11051 | - subq is attached to it1, and is evaluated for each row read from | ||
| 11052 | t1, potentially way more than 1. | ||
| 11053 | */ | ||
| 11054 | 10405 | const uint idx = subquery->in_cond_of_tab; | |
| 11055 |
2/4✓ Branch 0 taken 10405 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10405 times.
✗ Branch 3 not taken.
|
10405 | assert((int)idx >= 0 && idx < parent_join->tables); |
| 11056 |
1/2✓ Branch 0 taken 10405 times.
✗ Branch 1 not taken.
|
10405 | trace_parent.add("subq_attached_to_table", true); |
| 11057 | 10405 | QEP_TAB *const parent_tab = &parent_join->qep_tab[idx]; | |
| 11058 |
1/2✓ Branch 0 taken 10405 times.
✗ Branch 1 not taken.
|
10405 | trace_parent.add_utf8_table(parent_tab->table_ref); |
| 11059 | 10405 | parent_fanout = parent_tab->position()->rows_fetched; | |
| 11060 |
4/4✓ Branch 0 taken 991 times.
✓ Branch 1 taken 9414 times.
✓ Branch 2 taken 965 times.
✓ Branch 3 taken 9440 times.
|
11396 | if ((idx > parent_join->const_tables) && |
| 11061 |
2/2✓ Branch 0 taken 965 times.
✓ Branch 1 taken 26 times.
|
991 | !sj_is_materialize_strategy(parent_tab->position()->sj_strategy)) |
| 11062 | 965 | parent_fanout *= parent_tab[-1].position()->prefix_rowcount; | |
| 11063 | } else { | ||
| 11064 | /* | ||
| 11065 | Subquery is SELECT list, GROUP BY, ORDER BY, HAVING: it is evaluated | ||
| 11066 | at the end of the parent join's execution. | ||
| 11067 | It can be evaluated once per row-before-grouping: | ||
| 11068 | SELECT SUM(t1.col IN (subq)) FROM t1 GROUP BY expr; | ||
| 11069 | or once per row-after-grouping: | ||
| 11070 | SELECT SUM(t1.col) AS s FROM t1 GROUP BY expr HAVING s IN (subq), | ||
| 11071 | SELECT SUM(t1.col) IN (subq) FROM t1 GROUP BY expr | ||
| 11072 | It's hard to tell. We simply assume 'once per | ||
| 11073 | row-before-grouping'. | ||
| 11074 | |||
| 11075 | Another approximation: | ||
| 11076 | SELECT ... HAVING x IN (subq) LIMIT 1 | ||
| 11077 | best_rowcount=1 due to LIMIT, though HAVING (and thus the subquery) | ||
| 11078 | may be evaluated many times before HAVING becomes true and the limit | ||
| 11079 | is reached. | ||
| 11080 | */ | ||
| 11081 |
1/2✓ Branch 0 taken 5234 times.
✗ Branch 1 not taken.
|
5234 | trace_parent.add("subq_attached_to_join_result", true); |
| 11082 | 5234 | parent_fanout = static_cast<double>(parent_join->best_rowcount); | |
| 11083 | } | ||
| 11084 | } | ||
| 11085 | 19971 | subquery_executions *= parent_fanout; | |
| 11086 |
1/2✓ Branch 0 taken 19971 times.
✗ Branch 1 not taken.
|
19971 | trace_parent.add("fanout", parent_fanout); |
| 11087 | 19971 | const bool cacheable = parent_query_block->is_cacheable(); | |
| 11088 |
1/2✓ Branch 0 taken 19971 times.
✗ Branch 1 not taken.
|
19971 | trace_parent.add("cacheable", cacheable); |
| 11089 |
2/2✓ Branch 0 taken 15359 times.
✓ Branch 1 taken 4612 times.
|
19971 | if (cacheable) { |
| 11090 | // Parent executed only once | ||
| 11091 | 15359 | break; | |
| 11092 | } | ||
| 11093 | /* | ||
| 11094 | Parent query is executed once per outer row => go up to find number of | ||
| 11095 | outer rows. Example: | ||
| 11096 | SELECT ... IN(subq-with-in2exists WHERE ... IN (subq-with-mat)) | ||
| 11097 | */ | ||
| 11098 | 4612 | subquery = parent_join->query_expression()->item; | |
| 11099 |
2/2✓ Branch 0 taken 266 times.
✓ Branch 1 taken 4346 times.
|
4612 | if (subquery == nullptr) { |
| 11100 | // derived table, materialized only once | ||
| 11101 | 266 | break; | |
| 11102 | } | ||
| 11103 |
2/2✓ Branch 0 taken 4346 times.
✓ Branch 1 taken 15625 times.
|
24317 | } // for(;;) |
| 11104 | 15625 | return subquery_executions; | |
| 11105 | 15625 | } | |
| 11106 | |||
| 11107 | /** | ||
| 11108 | Optimize rollup specification. | ||
| 11109 | |||
| 11110 | Allocate objects needed for rollup processing. | ||
| 11111 | |||
| 11112 | @returns false if success, true if error. | ||
| 11113 | */ | ||
| 11114 | |||
| 11115 | 377 | bool JOIN::optimize_rollup() { | |
| 11116 | 377 | tmp_table_param.allow_group_via_temp_table = false; | |
| 11117 | 377 | rollup_state = RollupState::INITED; | |
| 11118 | 377 | tmp_table_param.group_parts = send_group_parts; | |
| 11119 | 377 | return false; | |
| 11120 | } | ||
| 11121 | |||
| 11122 | /** | ||
| 11123 | Refine the best_rowcount estimation based on what happens after tables | ||
| 11124 | have been joined: LIMIT and type of result sink. | ||
| 11125 | */ | ||
| 11126 | 1866809 | void JOIN::refine_best_rowcount() { | |
| 11127 | // If plan is const, 0 or 1 rows should be returned | ||
| 11128 |
3/4✓ Branch 0 taken 99398 times.
✓ Branch 1 taken 1767447 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 99398 times.
|
1866809 | assert(!plan_is_const() || best_rowcount <= 1); |
| 11129 | |||
| 11130 |
2/2✓ Branch 0 taken 99398 times.
✓ Branch 1 taken 1767457 times.
|
1866845 | if (plan_is_const()) return; |
| 11131 | |||
| 11132 | /* | ||
| 11133 | If a derived table, or a member of a UNION which itself forms a derived | ||
| 11134 | table: | ||
| 11135 | setting estimate to 0 or 1 row would mark the derived table as const. | ||
| 11136 | The row count is bumped to the nearest higher value, so that the | ||
| 11137 | query block will not be evaluated during optimization. | ||
| 11138 | */ | ||
| 11139 |
4/4✓ Branch 0 taken 366931 times.
✓ Branch 1 taken 1400526 times.
✓ Branch 2 taken 3613 times.
✓ Branch 3 taken 1763810 times.
|
2134354 | if (best_rowcount <= 1 && |
| 11140 |
2/2✓ Branch 0 taken 3613 times.
✓ Branch 1 taken 363284 times.
|
366931 | query_block->master_query_expression()->first_query_block()->linkage == |
| 11141 | DERIVED_TABLE_TYPE) | ||
| 11142 | 3613 | best_rowcount = PLACEHOLDER_TABLE_ROW_ESTIMATE; | |
| 11143 | |||
| 11144 | /* | ||
| 11145 | There will be no more rows than defined in the LIMIT clause. Use it | ||
| 11146 | as an estimate. If LIMIT 1 is specified, the query block will be | ||
| 11147 | considered "const", with actual row count 0 or 1. | ||
| 11148 | */ | ||
| 11149 | 1767423 | best_rowcount = std::min(best_rowcount, query_expression()->select_limit_cnt); | |
| 11150 | } | ||
| 11151 | |||
| 11152 | 147993 | mem_root_deque<Item *> *JOIN::get_current_fields() { | |
| 11153 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 147993 times.
|
147993 | assert((int)current_ref_item_slice >= 0); |
| 11154 |
2/2✓ Branch 0 taken 147989 times.
✓ Branch 1 taken 4 times.
|
147993 | if (current_ref_item_slice == REF_SLICE_SAVED_BASE) return fields; |
| 11155 | 4 | return &tmp_fields[current_ref_item_slice]; | |
| 11156 | } | ||
| 11157 | |||
| 11158 | 515865388 | const Cost_model_server *JOIN::cost_model() const { | |
| 11159 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 515865388 times.
|
515865388 | assert(thd != nullptr); |
| 11160 | 515865388 | return thd->cost_model(); | |
| 11161 | } | ||
| 11162 | |||
| 11163 | /** | ||
| 11164 | @} (end of group Query_Optimizer) | ||
| 11165 | */ | ||
| 11166 | |||
| 11167 | /** | ||
| 11168 | This function is used to get the key length of Item object on | ||
| 11169 | which one tmp field will be created during create_tmp_table. | ||
| 11170 | This function references KEY_PART_INFO::init_from_field(). | ||
| 11171 | |||
| 11172 | @param item A inner item of outer join | ||
| 11173 | |||
| 11174 | @return The length of a item to be as a key of a temp table | ||
| 11175 | */ | ||
| 11176 | |||
| 11177 | 9514 | static uint32 get_key_length_tmp_table(Item *item) { | |
| 11178 | 9514 | uint32 len = 0; | |
| 11179 | |||
| 11180 | 9514 | item = item->real_item(); | |
| 11181 |
2/2✓ Branch 0 taken 8012 times.
✓ Branch 1 taken 1502 times.
|
9514 | if (item->type() == Item::FIELD_ITEM) |
| 11182 | 8012 | len = ((Item_field *)item)->field->key_length(); | |
| 11183 | else | ||
| 11184 | 1502 | len = item->max_length; | |
| 11185 | |||
| 11186 |
2/2✓ Branch 0 taken 8380 times.
✓ Branch 1 taken 1134 times.
|
9514 | if (item->is_nullable()) len += HA_KEY_NULL_LENGTH; |
| 11187 | |||
| 11188 | // references KEY_PART_INFO::init_from_field() | ||
| 11189 | 9514 | enum_field_types type = item->data_type(); | |
| 11190 |
6/6✓ Branch 0 taken 9235 times.
✓ Branch 1 taken 279 times.
✓ Branch 2 taken 7594 times.
✓ Branch 3 taken 1641 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 7582 times.
|
9514 | if (type == MYSQL_TYPE_BLOB || type == MYSQL_TYPE_VARCHAR || |
| 11191 | type == MYSQL_TYPE_GEOMETRY) | ||
| 11192 | 1932 | len += HA_KEY_BLOB_LENGTH; | |
| 11193 | |||
| 11194 | 9514 | return len; | |
| 11195 | } | ||
| 11196 | |||
| 11197 | 4753192 | bool evaluate_during_optimization(const Item *item, const Query_block *select) { | |
| 11198 | /* | ||
| 11199 | Should only be called on items that are const_for_execution(), as those | ||
| 11200 | items are the only ones that are allowed to be evaluated during optimization | ||
| 11201 | in the first place. | ||
| 11202 | |||
| 11203 | Additionally, allow items that only access tables in JOIN::const_table_map. | ||
| 11204 | This should not be necessary, but the const_for_execution() property is not | ||
| 11205 | always updated correctly by update_used_tables() for certain subqueries. | ||
| 11206 | */ | ||
| 11207 |
3/4✓ Branch 0 taken 68 times.
✓ Branch 1 taken 4753223 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 68 times.
|
4753192 | assert(item->const_for_execution() || |
| 11208 | (item->used_tables() & ~select->join->const_table_map) == 0); | ||
| 11209 | |||
| 11210 | // If the Item does not access any tables, it can always be evaluated. | ||
| 11211 |
2/2✓ Branch 0 taken 4362384 times.
✓ Branch 1 taken 390970 times.
|
4753291 | if (item->const_item()) return true; |
| 11212 | |||
| 11213 |
4/4✓ Branch 0 taken 17760 times.
✓ Branch 1 taken 373230 times.
✓ Branch 2 taken 17743 times.
✓ Branch 3 taken 14 times.
|
390970 | return !item->has_subquery() || (select->active_options() & |
| 11214 | 390987 | OPTION_NO_SUBQUERY_DURING_OPTIMIZATION) == 0; | |
| 11215 | } | ||
| 11216 |